home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 676-700 / 681 / term / source.lha / termAux.c < prev    next >
C/C++ Source or Header  |  1992-05-09  |  65KB  |  3,343 lines

  1. /*
  2. **    $Id: termAux.c,v 1.12 92/05/08 20:50:59 olsen Sta Locker: olsen $
  3. **    $Revision: 1.12 $
  4. **    $Date: 92/05/08 20:50:59 $
  5. **
  6. **    Miscellaneous support routines
  7. **
  8. **    Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
  9. **        All Rights Reserved
  10. */
  11.  
  12. #include "termGlobal.h"
  13.  
  14.     /* Some handy positioning macros for StatusServer(). */
  15.  
  16. #define MoveItem(X,Y) Move(RPort,StatusOffset + X * 8,10 + Y * 13)
  17.  
  18. #define MoveSingle(X) Move(RPort,StatusOffset + X * 8,7)
  19.  
  20.     /* The following static strings are displayed in the status
  21.      * window.
  22.      */
  23.  
  24. STATIC UBYTE *ConfigFont[2] =
  25. {
  26.     "Topaz",
  27.     "IBM® "
  28. };
  29.  
  30. STATIC UBYTE *ConfigEmulation[4] =
  31. {
  32.     NULL,
  33.     NULL,
  34.     NULL,
  35.     NULL
  36. };
  37.  
  38. STATIC UBYTE *ConfigParity[5] =
  39. {
  40.     NULL,
  41.     NULL,
  42.     NULL,
  43.     NULL,
  44.     NULL
  45. };
  46.  
  47. STATIC UBYTE *ConfigStatus[7] =
  48. {
  49.     NULL,
  50.     NULL,
  51.     NULL,
  52.     NULL,
  53.     NULL,
  54.     NULL,
  55.     NULL
  56. };
  57.  
  58.     /* Block window nest count. */
  59.  
  60. STATIC WORD BlockNestCount;
  61.  
  62.     /* ExtractString():
  63.      *
  64.      *    Extracts a string from a list separated by `|' characters.
  65.      */
  66.  
  67. UBYTE * __regargs
  68. ExtractString(UBYTE *String,UBYTE *Destination,BYTE ReturnEnd)
  69. {
  70.     UBYTE *OldString;
  71.  
  72.     if(ReturnEnd)
  73.         OldString = NULL;
  74.     else
  75.         OldString = String;
  76.  
  77.     while(*String)
  78.     {
  79.         if(*String == '|')
  80.         {
  81.             *Destination = 0;
  82.  
  83.             String++;
  84.  
  85.             if(*String)
  86.                 return(String);
  87.             else
  88.                 return(OldString);
  89.         }
  90.         else
  91.             *Destination++ = *String++;
  92.     }
  93.  
  94.     *Destination = 0;
  95.  
  96.     return(OldString);
  97. }
  98.  
  99.     /* DeleteInterleavedBitMap():
  100.      *
  101.      *    Delete an interleaved bitmap as allocated by
  102.      *    CreateInterleavedBitMap().
  103.      */
  104.  
  105. VOID __regargs
  106. DeleteInterleavedBitMap(struct BitMap *SomeBitMap)
  107. {
  108.     FreeVec(SomeBitMap -> Planes[0]);
  109.  
  110.     FreeVec(SomeBitMap);
  111. }
  112.  
  113.     /* CreateInterleavedBitMap():
  114.      *
  115.      *    With special thanks to Leo Schwab, this routine will create an
  116.      *    interleaved BitMap structure suitable for optimized blitter
  117.      *    access.
  118.      */
  119.  
  120. struct BitMap * __regargs
  121. CreateInterleavedBitMap(LONG Width,LONG Height,WORD Depth)
  122. {
  123.         /* A single plane BitMap cannot be interleaved. */
  124.  
  125.     if(Depth > 1)
  126.     {
  127.         struct BitMap *SomeBitMap;
  128.  
  129.             /* Allocate space for the bitmap structure. */
  130.  
  131.         if(SomeBitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY))
  132.         {
  133.                 /* Initialize with standard values, so we can check
  134.                  * whether the current system will be able to handle
  135.                  * an interleaved bitmap of the expected size.
  136.                  */
  137.  
  138.             InitBitMap(SomeBitMap,Depth,Width,Height);
  139.  
  140.                 /* Check for old standard blitter limits. */
  141.  
  142.             if(Height * Depth > 1024 || SomeBitMap -> BytesPerRow * Depth > 126)
  143.             {
  144.                     /* The current space requirements will operate
  145.                      * correctly only on a system equipped with a
  146.                      * Fat Agnus (or successor) chip, let's see
  147.                      * if we can find one.
  148.                      */
  149.  
  150.                 if(!(GfxBase -> ChipRevBits0 & GFXF_BIG_BLITS))
  151.                 {
  152.                         /* Looks like a Big or old (A1000)
  153.                          * Agnus chip.
  154.                          */
  155.  
  156.                     FreeVec(SomeBitMap);
  157.  
  158.                     return(NULL);
  159.                 }
  160.                 else
  161.                 {
  162.                         /* Unlikely, put still not impossible: check for
  163.                          * Fat Agnus size limits...
  164.                          */
  165.  
  166.                     if(Height * Depth > 32768 || SomeBitMap -> BytesPerRow * Depth > 4096)
  167.                     {
  168.                         FreeVec(SomeBitMap);
  169.  
  170.                         return(NULL);
  171.                     }
  172.                 }
  173.             }
  174.  
  175.                 /* Initialize to interleaved BitMap values. */
  176.  
  177.             InitBitMap(SomeBitMap,1,Width,Height * Depth);
  178.  
  179.                 /* Allocate plane data. */
  180.  
  181.             if(SomeBitMap -> Planes[0] = (PLANEPTR)AllocVec(SomeBitMap -> BytesPerRow * SomeBitMap -> Rows,MEMF_CHIP))
  182.             {
  183.                 PLANEPTR    Base;
  184.                 WORD        i,
  185.                         Size;
  186.  
  187.                     /* Remember previous data. */
  188.  
  189.                 Base = SomeBitMap -> Planes[0];
  190.                 Size = SomeBitMap -> BytesPerRow;
  191.  
  192.                     /* Clear the bitmap. */
  193.  
  194.                 BltBitMap(SomeBitMap,0,0,SomeBitMap,0,0,Width,Height,0,~0,NULL);
  195.  
  196.                     /* Reinitialize. */
  197.  
  198.                 InitBitMap(SomeBitMap,Depth,Width,Height);
  199.  
  200.                     /* Modify for interleaved look. */
  201.  
  202.                 SomeBitMap -> BytesPerRow *= Depth;
  203.  
  204.                     /* Initialize the single planes. */
  205.  
  206.                 for(i = 0 ; i < Depth ; i++)
  207.                 {
  208.                     SomeBitMap -> Planes[i] = Base;
  209.  
  210.                     Base += Size;
  211.                 }
  212.  
  213.                     /* Return the ready bitmap. */
  214.  
  215.                 return(SomeBitMap);
  216.             }
  217.  
  218.                 /* Deallocate memory. */
  219.  
  220.             FreeVec(SomeBitMap);
  221.         }
  222.     }
  223.  
  224.         /* Return failure. */
  225.  
  226.     return(NULL);
  227. }
  228.  
  229.     /* GetListNode(LONG Offset,struct List *List):
  230.      *
  231.      *    Return the n-th Node entry in a standard exec list.
  232.      */
  233.  
  234. struct Node *
  235. GetListNode(LONG Offset,struct List *List)
  236. {
  237.     struct Node    *Node;
  238.     LONG         i;
  239.  
  240.     Node = List -> lh_Head;
  241.  
  242.     for(i = 0 ; i < Offset ; i++)
  243.     {
  244.         if(!Node -> ln_Succ -> ln_Succ)
  245.             return(NULL);
  246.  
  247.         Node = Node -> ln_Succ;
  248.     }
  249.  
  250.     return(Node);
  251. }
  252.  
  253.     /* GetConUnit():
  254.      *
  255.      *    Extract the ConUnit pointer from the current output stream
  256.      *    console.
  257.      */
  258.  
  259. struct ConUnit *
  260. GetConUnit(struct MsgPort *ConsoleTask)
  261. {
  262.     struct InfoData    *InfoData;
  263.     struct ConUnit    *ConUnit = NULL;
  264.  
  265.     if(!ConsoleTask)
  266.     {
  267.         ConsoleTask = (struct MsgPort *)((struct Process *)SysBase -> ThisTask) -> pr_ConsoleTask;
  268.  
  269.         if(!TypeOfMem(ConsoleTask))
  270.             return(NULL);
  271.     }
  272.  
  273.     if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_ANY|MEMF_CLEAR))
  274.     {
  275.             /* Send the inquiry packet to the console task. */
  276.  
  277.         if(DoPkt1(ConsoleTask,ACTION_DISK_INFO,MKBADDR(InfoData)))
  278.             ConUnit = (struct ConUnit *)((struct IOStdReq *)InfoData -> id_InUse) -> io_Unit;
  279.  
  280.         FreeVec(InfoData);
  281.     }
  282.  
  283.     return(ConUnit);
  284. }
  285.  
  286.     /* AddDownloadObject(UBYTE *Line):
  287.      *
  288.      *    Add another downloaded object to the list.
  289.      */
  290.  
  291. VOID
  292. AddDownloadObject(UBYTE *Line)
  293. {
  294.     struct Node *SomeNode;
  295.  
  296.         /* Allocate space for the node itself and the
  297.          * string to be put into the node name.
  298.          */
  299.  
  300.     if(SomeNode = (struct Node *)AllocVec(sizeof(struct Node) + strlen(Line) + 1,MEMF_ANY|MEMF_CLEAR))
  301.     {
  302.             /* Block list modification. */
  303.  
  304.         ObtainSemaphore(DownloadSemaphore);
  305.  
  306.             /* Enter the name. */
  307.  
  308.         SomeNode -> ln_Name = (UBYTE *)(SomeNode + 1);
  309.  
  310.             /* Copy the line over. */
  311.  
  312.         strcpy(SomeNode -> ln_Name,Line);
  313.  
  314.             /* Add it to the list. */
  315.  
  316.         AddTail(&DownloadList,SomeNode);
  317.  
  318.             /* Increment number of downloads. */
  319.  
  320.         DownloadLineCount++;
  321.  
  322.         ReleaseSemaphore(DownloadSemaphore);
  323.     }
  324. }
  325.  
  326.     /* ClearDownloadObjects():
  327.      *
  328.      *    Clear the list of downloaded objects.
  329.      */
  330.  
  331. VOID
  332. ClearDownloadObjects()
  333. {
  334.     struct Node *SomeNode,*NextNode;
  335.  
  336.     ObtainSemaphore(DownloadSemaphore);
  337.  
  338.     SomeNode = DownloadList . lh_Head;
  339.  
  340.     while(SomeNode -> ln_Succ)
  341.     {
  342.         NextNode = SomeNode -> ln_Succ;
  343.  
  344.         Remove(SomeNode);
  345.  
  346.         FreeVec(SomeNode);
  347.  
  348.         SomeNode = NextNode;
  349.     }
  350.  
  351.     DownloadNode = NULL;
  352.  
  353.     DownloadLineCount = 0;
  354.  
  355.     ReleaseSemaphore(DownloadSemaphore);
  356. }
  357.  
  358.     /* SequenceFilter(UBYTE Char):
  359.      *
  360.      *    Yet another byte sequence filter, this time it's the
  361.      *    ARexx interface to make the call.
  362.      */
  363.  
  364. struct ScanNode *
  365. SequenceFilter(UBYTE Char)
  366. {
  367.     struct ScanNode    *SomeNode,*Matching = NULL;
  368.     BYTE         Matches = 0;
  369.  
  370.         /* Convert input character to upper case. */
  371.  
  372.     Char = ToUpper(Char);
  373.  
  374.         /* Get the first node in the list. */
  375.  
  376.     SomeNode = (struct ScanNode *)SequenceList . lh_Head;
  377.  
  378.         /* Scan until the last node is found. */
  379.  
  380.     while(SomeNode -> Node . mln_Succ)
  381.     {
  382.             /* This sequence had a couple of matches. */
  383.  
  384.         if(SomeNode -> Count == SequenceCount)
  385.         {
  386.                 /* The next character in the sequence
  387.                  * still matches.
  388.                  */
  389.  
  390.             if(Char == SomeNode -> Sequence[SequenceCount])
  391.             {
  392.                     /* Increase number of matching
  393.                      * characters.
  394.                      */
  395.  
  396.                 SomeNode -> Count++;
  397.  
  398.                     /* If there's another character
  399.                      * in the sequence, increase
  400.                      * the match counter.
  401.                      */
  402.  
  403.                 if(SomeNode -> Sequence[SequenceCount + 1])
  404.                     Matches++;
  405.                 else
  406.                 {
  407.                         /* We were able to make
  408.                          * a perfect match.
  409.                          */
  410.  
  411.                     Matches = 0;
  412.  
  413.                     Matching = SomeNode;
  414.                 }
  415.             }
  416.         }
  417.  
  418.             /* Skip to the next node. */
  419.  
  420.         SomeNode = (struct ScanNode *)SomeNode -> Node . mln_Succ;
  421.     }
  422.  
  423.     if(!Matches)
  424.     {
  425.             /* Clear the list entry counters. */
  426.  
  427.         if(SequenceCount)
  428.         {
  429.             SomeNode = (struct ScanNode *)SequenceList . lh_Head;
  430.  
  431.             while(SomeNode -> Node . mln_Succ)
  432.             {
  433.                 SomeNode -> Count = 0;
  434.  
  435.                 SomeNode = (struct ScanNode *)SomeNode -> Node . mln_Succ;
  436.             }
  437.  
  438.             SequenceCount = 0;
  439.         }
  440.     }
  441.     else
  442.         SequenceCount++;
  443.  
  444.     return(Matching);
  445. }
  446.  
  447.     /* AddSequenceObject(UBYTE *Sequence):
  448.      *
  449.      *    Add another sequence to the list of byte sequences
  450.      *    the routine above will look at whilst parsing.
  451.      */
  452.  
  453. VOID
  454. AddSequenceObject(UBYTE *Sequence)
  455. {
  456.     struct ScanNode *SomeNode;
  457.  
  458.     if(SomeNode = AllocVec(sizeof(struct ScanNode) + strlen(Sequence) + 1,MEMF_ANY|MEMF_CLEAR))
  459.     {
  460.         WORD i;
  461.  
  462.         SomeNode -> Sequence = (UBYTE *)(SomeNode + 1);
  463.  
  464.         for(i = 0 ; i <= strlen(Sequence) ; i++)
  465.             SomeNode -> Sequence[i] = ToUpper(Sequence[i]);
  466.  
  467.         AddTail(&SequenceList,(struct Node *)SomeNode);
  468.     }
  469. }
  470.  
  471.     /* ClearSequenceObjects():
  472.      *
  473.      *    Clear the list of scan sequences.
  474.      */
  475.  
  476. VOID
  477. ClearSequenceObjects()
  478. {
  479.     struct Node *SomeNode,*NextNode;
  480.  
  481.     SomeNode = SequenceList . lh_Head;
  482.  
  483.     while(SomeNode -> ln_Succ)
  484.     {
  485.         NextNode = SomeNode -> ln_Succ;
  486.  
  487.         Remove(SomeNode);
  488.  
  489.         FreeVec(SomeNode);
  490.  
  491.         SomeNode = NextNode;
  492.     }
  493. }
  494.  
  495.     /* LogAction(UBYTE *String,...):
  496.      *
  497.      *    Write an action to the default log file.
  498.      */
  499.  
  500. VOID __stdargs
  501. LogAction(UBYTE *String,...)
  502. {
  503.     if(Config . LogActions && Config . LogFile[0])
  504.     {
  505.         UBYTE    DummyBuffer[512];
  506.         BPTR    File;
  507.  
  508.         va_list    VarArgs;
  509.  
  510.             /* Build a valid string. */
  511.  
  512.         va_start(VarArgs,String);
  513.         VSPrintf(DummyBuffer,String,VarArgs);
  514.         va_end(VarArgs);
  515.  
  516.             /* Does the log file already exist? */
  517.  
  518.         if(GetFileSize(Config . LogFile))
  519.         {
  520.                 /* It does, let's append the data. */
  521.  
  522.             if(File = Open(Config . LogFile,MODE_READWRITE))
  523.             {
  524.                 if(Seek(File,0,OFFSET_END) == -1)
  525.                 {
  526.                     Close(File);
  527.  
  528.                     File = NULL;
  529.                 }
  530.             }
  531.         }
  532.         else
  533.         {
  534.                 /* Create a new file. */
  535.  
  536.             if(File = Open(Config . LogFile,MODE_NEWFILE))
  537.                 FPrintf(File,LocaleString(MSG_TERMAUX_DATE_TIME_ACTION_TXT));
  538.         }
  539.  
  540.             /* The file is open, build the date/time string and
  541.              * write the log action.
  542.              */
  543.  
  544.         if(File)
  545.         {
  546.             UBYTE        TimeBuffer[20],DateBuffer[20];
  547.             struct DateTime    DateTime;
  548.  
  549.                 /* Obtain current time. */
  550.  
  551.             DateStamp(&DateTime . dat_Stamp);
  552.  
  553.                 /* Convert it to human readable form. */
  554.  
  555.             DateTime . dat_Format    = FORMAT_DOS;
  556.             DateTime . dat_Flags    = 0;
  557.             DateTime . dat_StrDay    = NULL;
  558.             DateTime . dat_StrDate    = DateBuffer;
  559.             DateTime . dat_StrTime    = TimeBuffer;
  560.  
  561.                 /* Conversion succeeded? */
  562.  
  563.             if(DateToStr(&DateTime))
  564.                 FPrintf(File,"%s %s %s\n",DateBuffer,TimeBuffer,DummyBuffer);
  565.  
  566.                 /* Done! */
  567.  
  568.             Close(File);
  569.         }
  570.     }
  571. }
  572.  
  573.     /* FlushMsg(struct Window *Window):
  574.      *
  575.      *    Cancel all pending messages of a window.
  576.      */
  577.  
  578. VOID
  579. FlushMsg(struct Window *Window)
  580. {
  581.     struct IntuiMessage *Massage;
  582.  
  583.     while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  584.         ReplyMsg(&Massage -> ExecMessage);
  585. }
  586.  
  587.     /* GetString(UBYTE *Prompt,UBYTE *Buffer):
  588.      *
  589.      *    Get a string from the user, very much the same as xpr_gets,
  590.      *    but also including the `Load File' gadget.
  591.      */
  592.  
  593. BYTE
  594. GetString(UBYTE *Prompt,UBYTE *Buffer)
  595. {
  596.     struct Gadget        *GadgetList = NULL;
  597.     struct Gadget        *GadgetArray[4];
  598.     struct Window        *PanelWindow;
  599.     UBYTE             DummyBuffer[256];
  600.     struct FileRequester    *FileRequest;
  601.     LONG             Width;
  602.     BYTE             Success = FALSE;
  603.  
  604.     if(CreateAllGetsGadgets(TRUE,Buffer,Prompt,&Width,&GadgetArray[0],&GadgetList,VisualInfo,Screen -> WBorTop + Screen -> Font -> ta_YSize + 1,Screen))
  605.     {
  606.         if(PanelWindow = OpenWindowTags(NULL,
  607.             WA_Width,    Width,
  608.             WA_Height,    58,
  609.             WA_Left,    (Screen -> Width - Width) >> 1,
  610.             WA_Top,        (Screen -> Height - 56) >> 1,
  611.             WA_Activate,    TRUE,
  612.             WA_DragBar,    TRUE,
  613.             WA_DepthGadget,    TRUE,
  614.             WA_CloseGadget,    TRUE,
  615.             WA_RMBTrap,    TRUE,
  616.             WA_CustomScreen,Screen,
  617.             WA_IDCMP,    IDCMP_GADGETDOWN | IDCMP_ACTIVEWINDOW | IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_VANILLAKEY | BUTTONIDCMP | STRINGIDCMP,
  618.             WA_Title,    LocaleString(MSG_GLOBAL_ENTER_TEXT_TXT),
  619.         TAG_DONE))
  620.         {
  621.             struct IntuiMessage    *Massage;
  622.             ULONG             Class,Code;
  623.             struct Gadget        *Gadget;
  624.             BYTE             Terminated = FALSE;
  625.  
  626.             PushWindow(PanelWindow);
  627.  
  628.             AddGList(PanelWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
  629.             RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
  630.             GT_RefreshWindow(PanelWindow,NULL);
  631.  
  632.             ActiveGadget = NULL;
  633.  
  634.             while(!Terminated)
  635.             {
  636.                 WaitPort(PanelWindow -> UserPort);
  637.  
  638.                 while(!Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(PanelWindow -> UserPort)))
  639.                 {
  640.                     Class    = Massage -> Class;
  641.                     Code    = Massage -> Code;
  642.                     Gadget    = (struct Gadget *)Massage -> IAddress;
  643.  
  644.                     GT_ReplyIMsg(Massage);
  645.  
  646.                     if(Class == IDCMP_VANILLAKEY)
  647.                         KeySelect(GadgetArray,3,Code,PanelWindow,&Gadget,&Class,&Code);
  648.  
  649.                     if(Class == IDCMP_GADGETDOWN)
  650.                     {
  651.                         if((Gadget -> GadgetType & GTYP_GTYPEMASK) == GTYP_STRGADGET)
  652.                             ActiveGadget = Gadget;
  653.                     }
  654.  
  655.                     if(Class == IDCMP_ACTIVEWINDOW && ActiveGadget)
  656.                         ActivateGadget(ActiveGadget,PanelWindow,NULL);
  657.  
  658.                     if(Class == IDCMP_CLOSEWINDOW)
  659.                         Terminated = TRUE;
  660.  
  661.                     if(Class == IDCMP_GADGETUP)
  662.                     {
  663.                         switch(Gadget -> GadgetID)
  664.                         {
  665.                             case 0: if(Code != '\t')
  666.                                 {
  667.                                     strcpy(Buffer,GT_STRING(GadgetArray[0]));
  668.  
  669.                                     Success = TRUE;
  670.  
  671.                                     Terminated = TRUE;
  672.                                 }
  673.  
  674.                                 break;
  675.  
  676.                             case 1:    strcpy(Buffer,GT_STRING(GadgetArray[0]));
  677.  
  678.                                 Success = TRUE;
  679.  
  680.                                 Terminated = TRUE;
  681.                                 break;
  682.  
  683.                             case 2:    BlockWindow(PanelWindow);
  684.  
  685.                                 if(FileRequest = GetFile(LocaleString(MSG_TERMAUX_LOAD_FILE_TXT),"","",DummyBuffer,NULL,FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_LOAD_TXT)))
  686.                                 {
  687.                                     GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
  688.                                         GTST_String,DummyBuffer,
  689.                                     TAG_DONE);
  690.  
  691.                                     FreeAslRequest(FileRequest);
  692.                                 }
  693.  
  694.                                 ReleaseWindow(PanelWindow);
  695.  
  696.                                 break;
  697.  
  698.                             case 3:    Terminated = TRUE;
  699.                                 break;
  700.                         }
  701.                     }
  702.                 }
  703.             }
  704.  
  705.             ActiveGadget = NULL;
  706.  
  707.             RemoveGList(PanelWindow,GadgetList,(UWORD)-1);
  708.  
  709.             PopWindow();
  710.  
  711.             CloseWindow(PanelWindow);
  712.         }
  713.     }
  714.  
  715.     FreeGadgets(GadgetList);
  716.  
  717.     return(Success);
  718. }
  719.  
  720.     /* WakeUp(struct Window *Window):
  721.      *
  722.      *    Pop a window to the front and alert the user.
  723.      */
  724.  
  725. VOID __regargs
  726. WakeUp(struct Window *Window,BYTE Activate)
  727. {
  728.     if(Window)
  729.     {
  730.         if(Window -> WScreen -> LeftEdge > 0)
  731.         {
  732.             if(Window -> WScreen -> TopEdge > 0)
  733.                 MoveScreen(Window -> WScreen,-Window -> WScreen -> LeftEdge,-Window -> WScreen -> TopEdge);
  734.             else
  735.                 MoveScreen(Window -> WScreen,-Window -> WScreen -> LeftEdge,0);
  736.         }
  737.         else
  738.         {
  739.             if(Window -> WScreen -> TopEdge > 0)
  740.                 MoveScreen(Window -> WScreen,0,-Window -> WScreen -> TopEdge);
  741.         }
  742.  
  743.         ScreenToFront(Window -> WScreen);
  744.  
  745.         if(Activate)
  746.             ActivateWindow(Window);
  747.     }
  748.  
  749.     Beep();
  750.  
  751.     if(Activate)
  752.         WaitTime(2,0);
  753. }
  754.  
  755.     /* SendAmigaDOSCommand(UBYTE *Name):
  756.      *
  757.      *    Let the current default Shell execute an AmigaDOS
  758.      *    command. Block until the command has returned.
  759.      */
  760.  
  761. VOID
  762. SendAmigaDOSCommand(UBYTE *Name)
  763. {
  764.     BYTE DummyBuffer[2];
  765.     BPTR File;
  766.  
  767.         /* Let the asynchronous Rexx server pick up and process
  768.          * all incoming messages rather than sending them to the
  769.          * main process (hopefully avoids deadlock situations).
  770.          */
  771.  
  772.     BatchMode = TRUE;
  773.  
  774.         /* Open the console window or whatever the user
  775.          * wants us to open here.
  776.          */
  777.  
  778.     if(File = Open(WindowName,MODE_NEWFILE))
  779.     {
  780.         struct ConUnit    *ConUnit = GetConUnit(((struct FileHandle *)BADDR(File)) -> fh_Type);
  781.         STRPTR         WindowSpec;
  782.  
  783.         if(ConUnit)
  784.         {
  785.             if(ConUnit -> cu_Window)
  786.                 BumpWindow(ConUnit -> cu_Window);
  787.         }
  788.  
  789.             /* Make the Shell execute the command. */
  790.  
  791.         SystemTags(Name,SYS_Output,File,TAG_DONE);
  792.  
  793.             /* Wait for some impressive user action. */
  794.  
  795.         if(IsInteractive(File) && (WindowSpec = FilePart(WindowName)))
  796.         {
  797.             BYTE IsAuto = FALSE;
  798.             WORD i;
  799.  
  800.             for(i = 0 ; i < strlen(WindowSpec) - 3 ; i++)
  801.             {
  802.                 if(!Strnicmp(&WindowSpec[i],"WAIT",4))
  803.                 {
  804.                     IsAuto = TRUE;
  805.  
  806.                     break;
  807.                 }
  808.             }
  809.  
  810.             if(!IsAuto)
  811.             {
  812.                 Write(File,LocaleString(MSG_TERMAUX_PRESS_RETURN_TO_CONTINUE_TXT),strlen(LocaleString(MSG_TERMAUX_PRESS_RETURN_TO_CONTINUE_TXT)));
  813.  
  814.                 Read(File,DummyBuffer,1);
  815.             }
  816.         }
  817.  
  818.         Close(File);
  819.     }
  820.  
  821.         /* Bring the `term' main screen to the front and
  822.          * fall back into asynchronous Rexx message processing.
  823.          */
  824.  
  825.     BumpWindow(Window);
  826.  
  827.     BatchMode = FALSE;
  828. }
  829.  
  830.     /* RexxBackgroundServer():
  831.      *
  832.      *    The background process to handle the rexx
  833.      *    massaging.
  834.      */
  835.  
  836. VOID __saveds
  837. RexxBackgroundServer()
  838. {
  839.     BPTR         OldCOS,OldCIS,NewCOS,NewCIS;
  840.     struct MsgPort    *OldConsoleTask,*ReplyPort;
  841.  
  842.     BYTE         DummyBuffer[2];
  843.  
  844.     struct RexxMsg    *RexxMsg;
  845.  
  846.     struct Process    *BackgroundProcess;
  847.     struct Message    *SetupMsg;
  848.  
  849.         /* Look who we are. */
  850.  
  851.     BackgroundProcess = (struct Process *)SysBase -> ThisTask;
  852.  
  853.         /* Wait for startup message. */
  854.  
  855.     WaitPort(&BackgroundProcess -> pr_MsgPort);
  856.  
  857.         /* Pick the message up. */
  858.  
  859.     SetupMsg = GetMsg(&BackgroundProcess -> pr_MsgPort);
  860.  
  861.         /* Create a reply port the Rexx message is to
  862.          * return to after processing.
  863.          */
  864.  
  865.     if(ReplyPort = (struct MsgPort *)CreateMsgPort())
  866.     {
  867.             /* Remember previous I/O streams and
  868.              * console handler.
  869.              */
  870.  
  871.         OldCOS        = BackgroundProcess -> pr_COS;
  872.         OldCIS        = BackgroundProcess -> pr_CIS;
  873.  
  874.         OldConsoleTask    = BackgroundProcess -> pr_ConsoleTask;
  875.  
  876.             /* The following lines perform an `almost illegal'
  877.              * action: new console I/O streams are opened for
  878.              * the `term' main process. This is due to a rather
  879.              * helpful Rexx server feature. Errors, messages
  880.              * and other data are sent to the current output
  881.              * stream.
  882.              */
  883.  
  884.         if(NewCIS = Open(WindowName,MODE_NEWFILE))
  885.         {
  886.             struct FileHandle    *FileHandle = (struct FileHandle *)BADDR(NewCIS);
  887.             struct ConUnit        *ConUnit = GetConUnit(((struct FileHandle *)BADDR(NewCIS)) -> fh_Type);
  888.  
  889.                 /* Lock until we're done with the forgery. */
  890.  
  891.             Forbid();
  892.  
  893.             BackgroundProcess -> pr_ConsoleTask    = (APTR)FileHandle -> fh_Type;
  894.  
  895.             BackgroundProcess -> pr_CIS        = NewCIS;
  896.             BackgroundProcess -> pr_COS        = NewCOS = Open("*",MODE_NEWFILE);
  897.  
  898.             Permit();
  899.  
  900.             RexxWindow = NULL;
  901.  
  902.             if(ConUnit)
  903.             {
  904.                 if(RexxWindow = ConUnit -> cu_Window)
  905.                     BumpWindow(RexxWindow);
  906.             }
  907.  
  908.                 /* Send the command and wait for a reply. */
  909.  
  910.             if(SendRexxCommand(ReplyPort,SetupMsg -> mn_Node . ln_Name,".term",TermIDString))
  911.             {
  912.                 ULONG SignalSet;
  913.  
  914.                 do
  915.                 {
  916.                     SignalSet = Wait((1 << ReplyPort -> mp_SigBit) | SIGBREAKF_CTRL_C);
  917.  
  918.                     if(SignalSet & SIGBREAKF_CTRL_C)
  919.                         Signal(ThisProcess,SIGBREAKF_CTRL_D);
  920.                 }
  921.                 while(!(SignalSet & (1 << ReplyPort -> mp_SigBit)));
  922.  
  923.                     /* Pick up the RexxMsg (SendRexxCommand
  924.                      * had allocated it for us) and
  925.                      * examine the return codes.
  926.                      */
  927.  
  928.                 if(RexxMsg = (struct RexxMsg *)GetMsg(ReplyPort))
  929.                 {
  930.                     if(!ExitQuietly)
  931.                     {
  932.                         STRPTR WindowSpec;
  933.  
  934.                         /* This doesn't look too
  935.                          * good, does it?
  936.                          */
  937.  
  938.                         if(RexxMsg -> rm_Result1)
  939.                             FPrintf(NewCIS,LocaleString(MSG_TERMAUX_COMMAND_HAS_TERMINATED_TXT),SetupMsg -> mn_Node . ln_Name,RexxMsg -> rm_Result1,RexxMsg -> rm_Result2);
  940.  
  941.                         /* Show our hand and return
  942.                          * to the usual business.
  943.                          */
  944.  
  945.                         if(IsInteractive(NewCIS) && (WindowSpec = FilePart(WindowName)))
  946.                         {
  947.                             BYTE IsAuto = FALSE;
  948.                             WORD i;
  949.  
  950.                             for(i = 0 ; i < strlen(WindowSpec) - 3 ; i++)
  951.                             {
  952.                                 if(!Strnicmp(&WindowSpec[i],"WAIT",4))
  953.                                 {
  954.                                     IsAuto = TRUE;
  955.  
  956.                                     break;
  957.                                 }
  958.                             }
  959.  
  960.                             if(!IsAuto)
  961.                             {
  962.                                 Write(NewCIS,LocaleString(MSG_TERMAUX_PRESS_RETURN_TO_CONTINUE_TXT),strlen(LocaleString(MSG_TERMAUX_PRESS_RETURN_TO_CONTINUE_TXT)));
  963.  
  964.                                 Read(NewCIS,DummyBuffer,1);
  965.                             }
  966.                         }
  967.  
  968.                         Term2Front();
  969.                     }
  970.                     else
  971.                         ExitQuietly = FALSE;
  972.  
  973.                         /* Release the message. */
  974.  
  975.                     FreeRexxCommand(RexxMsg);
  976.                 }
  977.             }
  978.  
  979.             Forbid();
  980.  
  981.             RexxWindow = NULL;
  982.  
  983.             Permit();
  984.  
  985.             BumpWindow(Window);
  986.  
  987.                 /* Close our fake I/O streams. */
  988.  
  989.             Forbid();
  990.  
  991.             Close(NewCIS);
  992.             Close(NewCOS);
  993.  
  994.                 /* And install the previous pointers. */
  995.  
  996.             BackgroundProcess -> pr_ConsoleTask    = (APTR)OldConsoleTask;
  997.  
  998.             BackgroundProcess -> pr_CIS        = OldCIS;
  999.             BackgroundProcess -> pr_COS        = OldCOS;
  1000.  
  1001.             Permit();
  1002.         }
  1003.  
  1004.             /* Remove the reply port. */
  1005.  
  1006.         DeleteMsgPort(ReplyPort);
  1007.     }
  1008.  
  1009.         /* We are done, lock and reply the message causing the
  1010.          * main process to return to the input loop.
  1011.          */
  1012.  
  1013.     Forbid();
  1014.  
  1015.     ReplyMsg(SetupMsg);
  1016. }
  1017.  
  1018.     /* SendARexxCommand(UBYTE *Name):
  1019.      *
  1020.      *    Let the ARexx server execute a command (or a script
  1021.      *    file if necessary) and block until the command
  1022.      *    has returned.
  1023.      */
  1024.  
  1025. VOID
  1026. SendARexxCommand(UBYTE *Name)
  1027. {
  1028.     struct Process    *BackgroundProcess;
  1029.     struct Message    *SetupMsg;
  1030.     struct MsgPort    *ReplyPort;
  1031.  
  1032.     ULONG         SignalSet;
  1033.  
  1034.         /* Create a reply port for the info message. */
  1035.  
  1036.     if(ReplyPort = CreateMsgPort())
  1037.     {
  1038.             /* Allocate the message body. */
  1039.  
  1040.         if(SetupMsg = (struct Message *)AllocVec(sizeof(struct Message),MEMF_ANY|MEMF_CLEAR))
  1041.         {
  1042.                 /* Set up the message itself. */
  1043.  
  1044.             SetupMsg -> mn_Node . ln_Name    = Name;
  1045.             SetupMsg -> mn_ReplyPort    = ReplyPort;
  1046.             SetupMsg -> mn_Length        = sizeof(struct Message);
  1047.  
  1048.                 /* Create the background process which will
  1049.                  * handle all the messy rexx message sending
  1050.                  * for us.
  1051.                  */
  1052.  
  1053.             if(BackgroundProcess = (struct Process *)CreateNewProcTags(
  1054.                 NP_Entry,    RexxBackgroundServer,
  1055.                 NP_Name,    "term ARexx background process",
  1056.                 NP_StackSize,    16384,
  1057.             TAG_END))
  1058.             {
  1059.                 SetSignal(0,SIGBREAKF_CTRL_D);
  1060.  
  1061.                     /* Send the startup message. */
  1062.  
  1063.                 PutMsg(&BackgroundProcess -> pr_MsgPort,SetupMsg);
  1064.  
  1065.                     /* Go into loop and wait for the
  1066.                      * background process to return.
  1067.                      */
  1068.  
  1069.                 FOREVER
  1070.                 {
  1071.                     SignalSet = Wait(SIG_REXX | (1 << ReplyPort -> mp_SigBit));
  1072.  
  1073.                         /* Yet another rexx message. */
  1074.  
  1075.                     if(SignalSet & SIG_REXX)
  1076.                         HandleRexx();
  1077.  
  1078.                         /* The background server has
  1079.                          * finished.
  1080.                          */
  1081.  
  1082.                     if(SignalSet & (1 << ReplyPort -> mp_SigBit))
  1083.                         break;
  1084.                 }
  1085.  
  1086.                 SetSignal(0,SIGBREAKF_CTRL_D);
  1087.             }
  1088.  
  1089.                 /* Free the message. */
  1090.  
  1091.             FreeVec(SetupMsg);
  1092.         }
  1093.  
  1094.             /* Delete the reply port. */
  1095.  
  1096.         DeleteMsgPort(ReplyPort);
  1097.     }
  1098. }
  1099.  
  1100.     /* ahtoi(UBYTE *String):
  1101.      *
  1102.      *    Turn a hexadecimal string into an integer (borrowed from
  1103.      *    Matt Dillon's dmouse.c).
  1104.      */
  1105.  
  1106. LONG
  1107. ahtoi(UBYTE *String)
  1108. {
  1109.     LONG Value = 0;
  1110.     UBYTE c;
  1111.  
  1112.     while(c = *String)
  1113.     {
  1114.         Value <<= 4;
  1115.  
  1116.         if(c >= '0' && c <= '9')
  1117.             Value |= (c & 15);
  1118.         else
  1119.             Value |= (c & 15) + 9;
  1120.  
  1121.         ++String;
  1122.     }
  1123.  
  1124.     return(Value);
  1125. }
  1126.  
  1127.     /* BlockWindow(struct Window *Window):
  1128.      *
  1129.      *    Block a window (show a wait mouse pointer, block
  1130.      *    windows, custom and system gadgets) by adding
  1131.      *    an invisible requester to it.
  1132.      */
  1133.  
  1134. VOID __regargs
  1135. BlockWindow(struct Window *Window)
  1136. {
  1137.     if(Window)
  1138.     {
  1139.         struct Requester    *InvisibleRequest = NULL;
  1140.         WORD             i;
  1141.  
  1142.         Forbid();
  1143.  
  1144.             /* Is this window already on the list? */
  1145.  
  1146.         for(i = 0 ; i < 10 ; i++)
  1147.         {
  1148.             if(RequesterList[i] . RWindow == Window)
  1149.             {
  1150.                 Permit();
  1151.  
  1152.                 return;
  1153.             }
  1154.         }
  1155.  
  1156.             /* Look for an empty slot. */
  1157.  
  1158.         for(i = 0 ; i < 10 ; i++)
  1159.         {
  1160.             if(!RequesterList[i] . RWindow)
  1161.             {
  1162.                 InvisibleRequest = &RequesterList[i];
  1163.  
  1164.                 InvisibleRequest -> RWindow = (struct Window *)~0;
  1165.  
  1166.                 break;
  1167.             }
  1168.         }
  1169.  
  1170.         Permit();
  1171.  
  1172.             /* Install the wait mouse pointer. */
  1173.  
  1174.         SetWait(Window);
  1175.  
  1176.             /* Install the requester if possible. */
  1177.  
  1178.         if(InvisibleRequest)
  1179.             Request(InvisibleRequest,Window);
  1180.     }
  1181. }
  1182.  
  1183.     /* ReleaseWindow(struct Window *Window):
  1184.      *
  1185.      *    Release a window blocked by `BlockWindow()'.
  1186.      */
  1187.  
  1188. VOID __regargs
  1189. ReleaseWindow(struct Window *Window)
  1190. {
  1191.     if(Window)
  1192.     {
  1193.         struct Requester    *InvisibleRequest = NULL;
  1194.         WORD             i;
  1195.  
  1196.             /* Search all slots for the requester to block this window. */
  1197.  
  1198.         for(i = 0 ; i < 10 ; i++)
  1199.         {
  1200.             if(RequesterList[i] . RWindow == Window)
  1201.             {
  1202.                 InvisibleRequest = &RequesterList[i];
  1203.  
  1204.                 break;
  1205.             }
  1206.         }
  1207.  
  1208.             /* Restore the mouse pointer. */
  1209.  
  1210.         ClearPointer(Window);
  1211.  
  1212.             /* If disabled, restore the window. */
  1213.  
  1214.         if(InvisibleRequest)
  1215.         {
  1216.                 /* End the requester activity. */
  1217.  
  1218.             EndRequest(InvisibleRequest,Window);
  1219.  
  1220.                 /* Reset it to zeroes. */
  1221.  
  1222.             memset(InvisibleRequest,0,sizeof(struct Requester));
  1223.         }
  1224.     }
  1225. }
  1226.  
  1227.     /* BlockWindows():
  1228.      *
  1229.      *    Block the main window and the status window (i.e. disable
  1230.      *    the menu and attach a wait pointer).
  1231.      */
  1232.  
  1233. VOID
  1234. BlockWindows()
  1235. {
  1236.     if(!(BlockNestCount++))
  1237.     {
  1238.         BlockWindow(Window);
  1239.         BlockWindow(StatusWindow);
  1240.         BlockWindow(PacketWindow);
  1241.         BlockWindow(FastWindow);
  1242.         BlockWindow(ReviewWindow);
  1243.  
  1244.         WeAreBlocking = TRUE;
  1245.     }
  1246. }
  1247.  
  1248.     /* ReleaseWindows():
  1249.      *
  1250.      *    Reenable the menus and clear the wait pointer.
  1251.      */
  1252.  
  1253. VOID
  1254. ReleaseWindows()
  1255. {
  1256.     if(!(--BlockNestCount))
  1257.     {
  1258.         ReleaseWindow(Window);
  1259.         ReleaseWindow(StatusWindow);
  1260.         ReleaseWindow(PacketWindow);
  1261.         ReleaseWindow(FastWindow);
  1262.         ReleaseWindow(ReviewWindow);
  1263.  
  1264.         WeAreBlocking = FALSE;
  1265.     }
  1266. }
  1267.  
  1268.     /* LineRead(BPTR File,UBYTE *Buffer,LONG MaxChars):
  1269.      *
  1270.      *    Read a few bytes from a file (à la gets).
  1271.      */
  1272.  
  1273. LONG
  1274. LineRead(BPTR File,UBYTE *Buffer,LONG MaxChars)
  1275. {
  1276.     STATIC    UBYTE    Data[1024];
  1277.  
  1278.     STATIC    LONG    RIdx = 0,
  1279.             RLen = 0;
  1280.  
  1281.         LONG    BytesRead = 0,
  1282.             i;
  1283.  
  1284.     if(File)
  1285.     {
  1286.         for(i = 0 ; i < MaxChars ; i++)
  1287.         {
  1288.             if(RIdx >= RLen)
  1289.             {
  1290.                 RLen = Read(File,Data,1024);
  1291.  
  1292.                 RIdx = 0;
  1293.  
  1294.                 if(RLen <= 0)
  1295.                 {
  1296.                     Buffer[i] = 0;
  1297.  
  1298.                     return(BytesRead);
  1299.                 }
  1300.             }
  1301.  
  1302.             BytesRead++;
  1303.  
  1304.             if((Buffer[i] = Data[RIdx++]) == '\n')
  1305.             {
  1306.                 Buffer[i + 1] = 0;
  1307.  
  1308.                 return(BytesRead);
  1309.             }
  1310.         }
  1311.  
  1312.         return(BytesRead);
  1313.     }
  1314.     else
  1315.         RIdx = RLen = 0;
  1316. }
  1317.  
  1318.     /* FlowInit():
  1319.      *
  1320.      *    Set up the data flow parser. The parser scans the serial
  1321.      *    output data for more or less interesting modem output
  1322.      *    (carrier lost, connect, etc.).
  1323.      */
  1324.  
  1325. VOID
  1326. FlowInit()
  1327. {
  1328.     FlowInfo . Changed = FALSE;
  1329.  
  1330.     FlowInfo . NoCarrier = FlowInfo . ZModemUpload = FlowInfo . Connect = FlowInfo . Voice = FlowInfo . Ring = FlowInfo . Busy = FlowInfo . NoDialTone = FALSE;
  1331.  
  1332.     if(Config . NoCarrier[0])
  1333.         SPrintf(AttentionBuffers[0],"%s\r",Config . NoCarrier);
  1334.     else
  1335.         AttentionBuffers[0][0] = 0;
  1336.  
  1337.     if(Config . Ring[0])
  1338.         SPrintf(AttentionBuffers[1],"%s\r",Config . Ring);
  1339.     else
  1340.         AttentionBuffers[1][0] = 0;
  1341.  
  1342.     if(Config . Voice[0])
  1343.         SPrintf(AttentionBuffers[2],"%s\r",Config . Voice);
  1344.     else
  1345.         AttentionBuffers[2][0] = 0;
  1346.  
  1347.     if(Config . Busy[0])
  1348.         SPrintf(AttentionBuffers[6],"%s\r",Config . Busy);
  1349.     else
  1350.         AttentionBuffers[6][0] = 0;
  1351.  
  1352.     if(Config . NoDialTone[0])
  1353.         SPrintf(AttentionBuffers[7],"%s\r",Config . NoDialTone);
  1354.     else
  1355.         AttentionBuffers[7][0] = 0;
  1356.  
  1357.     strcpy(AttentionBuffers[3],Config . Connect);
  1358.  
  1359.     strcpy(AttentionBuffers[4],"*\030B01");
  1360.     strcpy(AttentionBuffers[5],"**\030B01");
  1361.  
  1362.     FlowCount = 0;
  1363.  
  1364.     memset(&AttentionCount[0],0,8);
  1365.  
  1366.     BaudPending = FALSE;
  1367.  
  1368.     FullCheck = FALSE;
  1369. }
  1370.  
  1371.     /* FlowFilter(UBYTE Char):
  1372.      *
  1373.      *    Send a character through the data flow parser and look
  1374.      *    if it's part of a modem message.
  1375.      */
  1376.  
  1377. VOID
  1378. FlowFilter(UBYTE Char)
  1379. {
  1380.     if(Char)
  1381.     {
  1382.         STATIC    BYTE IgnoreChar;
  1383.             BYTE i,Matches = 0,Start,End,WasOnline = Online;
  1384.  
  1385.             /* Full data check is a lot slower than looking for
  1386.              * just a single sequence (such as the `CONNECT'
  1387.              * below). This mode is reserved for the dial panel.
  1388.              */
  1389.  
  1390.         if(FullCheck)
  1391.         {
  1392.             Start    = 0;
  1393.             End    = 8;
  1394.         }
  1395.         else
  1396.         {
  1397.             Start    = 0;
  1398.  
  1399.             if(UsesZModem)
  1400.                 End = 6;
  1401.             else
  1402.                 End = 4;
  1403.         }
  1404.  
  1405.             /* We already got a `CONNECT' and the
  1406.              * `connect auto-baud' feature is enabled.
  1407.              * Continue scanning the serial output
  1408.              * data for the actual baud rate.
  1409.              */
  1410.  
  1411.         if(BaudPending)
  1412.         {
  1413.             if(Char >= '0' && Char <= '9')
  1414.             {
  1415.                 BaudBuffer[BaudCount++] = Char;
  1416.  
  1417.                 if(IgnoreChar)
  1418.                     IgnoreChar = 0;
  1419.             }
  1420.             else
  1421.             {
  1422.                     /* The scanner has found a
  1423.                      * non-numerical character.
  1424.                      * This is either a blank
  1425.                      * space or something else.
  1426.                      * The latter tells us
  1427.                      * that the baud rate has
  1428.                      * been identified and is
  1429.                      * ready to be used.
  1430.                      */
  1431.  
  1432.                 if(Char != IgnoreChar)
  1433.                 {
  1434.                     BaudBuffer[BaudCount] = 0;
  1435.  
  1436.                     BaudPending = FALSE;
  1437.                 }
  1438.             }
  1439.         }
  1440.  
  1441.         if(!BaudPending)
  1442.         {
  1443.                 /* Scan all ID strings for matches. */
  1444.  
  1445.             for(i = Start ; i < End ; i++)
  1446.             {
  1447.                     /* This sequence is a probable
  1448.                      * match.
  1449.                      */
  1450.  
  1451.                 if(AttentionCount[i] == FlowCount)
  1452.                 {
  1453.                         /* Does the character
  1454.                          * fit into the sequence?
  1455.                          */
  1456.  
  1457.                     if(Char == AttentionBuffers[i][FlowCount])
  1458.                     {
  1459.                             /* Increment the
  1460.                              * number of matching
  1461.                              * characters in this
  1462.                              * sequence.
  1463.                              */
  1464.  
  1465.                         AttentionCount[i]++;
  1466.  
  1467.                             /* Did we hit the
  1468.                              * last character
  1469.                              * in the sequence?
  1470.                              */
  1471.  
  1472.                         if(AttentionBuffers[i][FlowCount + 1])
  1473.                             Matches++;
  1474.                         else
  1475.                         {
  1476.                             Matches = 0;
  1477.  
  1478.                                 /* We've got a valid
  1479.                                  * sequence, now look
  1480.                                  * which flags to change.
  1481.                                  */
  1482.  
  1483.                             switch(i)
  1484.                             {
  1485.                                     /* We got a `no carrier' message. */
  1486.  
  1487.                                 case 0:    if(Config . CheckCarrier)
  1488.                                     {
  1489.                                         WriteRequest -> IOSer . io_Command = SDCMD_QUERY;
  1490.  
  1491.                                         DoIO(WriteRequest);
  1492.  
  1493.                                             /* Are we to take a look at the carrier bit
  1494.                                              * and if so, is the carrier still
  1495.                                              * present?
  1496.                                              */
  1497.  
  1498.                                         if(!(WriteRequest -> io_Status & (1 << 5)))
  1499.                                             break;
  1500.                                     }
  1501.  
  1502.                                     if(!FlowInfo . NoCarrier)
  1503.                                     {
  1504.                                         FlowInfo . NoCarrier    = TRUE;
  1505.                                         FlowInfo . Changed    = TRUE;
  1506.                                     }
  1507.  
  1508.                                     Online = FALSE;
  1509.  
  1510.                                         /* Clear the password. */
  1511.  
  1512.                                     Password[0] = 0;
  1513.                                     UserName[0] = 0;
  1514.  
  1515.                                     if(WasOnline)
  1516.                                     {
  1517.                                         if(CurrentPay && ChosenEntry)
  1518.                                             LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_COST_TXT),CreateSum(CurrentPay,TRUE));
  1519.                                         else
  1520.                                             LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));
  1521.  
  1522.                                         Say(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));
  1523.                                     }
  1524.  
  1525.                                     break;
  1526.  
  1527.                                     /* Got another call. */
  1528.  
  1529.                                 case 1:    if(!FlowInfo . Ring)
  1530.                                     {
  1531.                                         FlowInfo . Ring        = TRUE;
  1532.                                         FlowInfo . Changed    = TRUE;
  1533.                                     }
  1534.  
  1535.                                     break;
  1536.  
  1537.                                     /* Got a voice call. */
  1538.  
  1539.                                 case 2:    if(!FlowInfo . Voice)
  1540.                                     {
  1541.                                         FlowInfo . Voice    = TRUE;
  1542.                                         FlowInfo . Changed    = TRUE;
  1543.                                     }
  1544.  
  1545.                                     break;
  1546.  
  1547.                                     /* Got a connect message. */
  1548.  
  1549.                                 case 3:    if(!FlowInfo . Connect)
  1550.                                     {
  1551.                                         FlowInfo . Connect    = TRUE;
  1552.                                         FlowInfo . Changed    = TRUE;
  1553.                                     }
  1554.  
  1555.                                     if(Config . ConnectAutoBaud)
  1556.                                     {
  1557.                                         BaudBuffer[0]    = 0;
  1558.  
  1559.                                         BaudPending    = TRUE;
  1560.                                         BaudCount    = 0;
  1561.  
  1562.                                         IgnoreChar    = ' ';
  1563.                                     }
  1564.  
  1565.                                     break;
  1566.  
  1567.                                     /* Got the ZModem inquiry sequence. */
  1568.  
  1569.                                 case 4:
  1570.                                 case 5:    if(!FlowInfo . ZModemUpload)
  1571.                                     {
  1572.                                         FlowInfo . ZModemUpload    = TRUE;
  1573.                                         FlowInfo . Changed    = TRUE;
  1574.                                     }
  1575.  
  1576.                                     break;
  1577.  
  1578.                                     /* Line is busy. */
  1579.  
  1580.                                 case 6:    if(!FlowInfo . Busy)
  1581.                                     {
  1582.                                         FlowInfo . Busy        = TRUE;
  1583.                                         FlowInfo . Changed    = TRUE;
  1584.                                     }
  1585.  
  1586.                                     break;
  1587.  
  1588.                                 case 7:    if(!FlowInfo . NoDialTone)
  1589.                                     {
  1590.                                         FlowInfo . NoDialTone    = TRUE;
  1591.                                         FlowInfo . Changed    = TRUE;
  1592.                                     }
  1593.  
  1594.                                     break;
  1595.                             }
  1596.                         }
  1597.                     }
  1598.                 }
  1599.             }
  1600.  
  1601.                 /* We've got a good match (recognized
  1602.                  * a sequence, so reset the data flow
  1603.                  * scanner.
  1604.                  */
  1605.  
  1606.             if(!Matches)
  1607.             {
  1608.                 if(FlowCount)
  1609.                 {
  1610.                     FlowCount = 0;
  1611.  
  1612.                     memset(&AttentionCount[0],0,8);
  1613.                 }
  1614.             }
  1615.             else
  1616.                 FlowCount++;
  1617.         }
  1618.         else
  1619.         {
  1620.                 /* This checks for just a single sequence:
  1621.                  * the notorious `NO CARRIER'.
  1622.                  */
  1623.  
  1624.             if(AttentionCount[0] == FlowCount)
  1625.             {
  1626.                 if(Char == AttentionBuffers[0][FlowCount])
  1627.                 {
  1628.                     AttentionCount[0]++;
  1629.  
  1630.                     if(AttentionBuffers[0][FlowCount + 1])
  1631.                         Matches++;
  1632.                     else
  1633.                     {
  1634.                         Matches = 0;
  1635.  
  1636.                         if(!FlowInfo . NoCarrier)
  1637.                         {
  1638.                             FlowInfo . NoCarrier    = TRUE;
  1639.                             FlowInfo . Changed    = TRUE;
  1640.                         }
  1641.  
  1642.                         Online = FALSE;
  1643.  
  1644.                             /* Clear the password. */
  1645.  
  1646.                         Password[0] = 0;
  1647.                         UserName[0] = 0;
  1648.  
  1649.                         if(WasOnline)
  1650.                         {
  1651.                             if(CurrentPay)
  1652.                                 LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_COST_TXT),CreateSum(CurrentPay,TRUE));
  1653.                             else
  1654.                                 LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));
  1655.  
  1656.                             Say(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));
  1657.                         }
  1658.                     }
  1659.                 }
  1660.             }
  1661.  
  1662.             if(!Matches)
  1663.             {
  1664.                 if(FlowCount)
  1665.                 {
  1666.                     FlowCount = 0;
  1667.  
  1668.                     memset(&AttentionCount[0],0,8);
  1669.                 }
  1670.             }
  1671.             else
  1672.                 FlowCount++;
  1673.         }
  1674.     }
  1675. }
  1676.  
  1677.     /* LoadMacros(UBYTE *Name,struct MacroKeys *Keys):
  1678.      *
  1679.      *    Load the keyboard macros from a file.
  1680.      */
  1681.  
  1682. BYTE
  1683. LoadMacros(UBYTE *Name,struct MacroKeys *Keys)
  1684. {
  1685.     struct IFFHandle    *Handle;
  1686.     BYTE             Success = FALSE;
  1687.     struct StoredProperty    *Prop;
  1688.     struct TermInfo        *TermInfo;
  1689.  
  1690.     if(Handle = AllocIFF())
  1691.     {
  1692.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  1693.         {
  1694.             InitIFFasDOS(Handle);
  1695.  
  1696.             if(!OpenIFF(Handle,IFFF_READ))
  1697.             {
  1698.                 /* Collect version number ID if
  1699.                  * available.
  1700.                  */
  1701.  
  1702.                 if(!PropChunks(Handle,&VersionProps[0],1))
  1703.                 {
  1704.                     /* The following line tells iffparse to stop at the
  1705.                      * very beginning of a `Type' chunk contained in a
  1706.                      * `TERM' FORM chunk.
  1707.                      */
  1708.  
  1709.                     if(!StopChunk(Handle,'TERM','KEYS'))
  1710.                     {
  1711.                         /* Parse the file... */
  1712.  
  1713.                         if(!ParseIFF(Handle,IFFPARSE_SCAN))
  1714.                         {
  1715.                             /* Did we get a version ID? */
  1716.  
  1717.                             if(Prop = FindProp(Handle,'TERM','VERS'))
  1718.                             {
  1719.                                 TermInfo = (struct TermInfo *)Prop -> sp_Data;
  1720.  
  1721.                                 /* Is it the file format we are able
  1722.                                  * to read?
  1723.                                  */
  1724.  
  1725.                                 if((TermInfo -> Version > TermVersion) || (TermInfo -> Version == TermVersion && TermInfo -> Revision > TermRevision) || (TermInfo -> Version == 1 && TermInfo -> Revision < 6))
  1726.                                 {
  1727.                                         /* Probably an older revision. */
  1728.  
  1729.                                     if(TermInfo -> Version == 1 && TermInfo -> Revision < 6)
  1730.                                     {
  1731.                                         memset(Keys,0,sizeof(struct MacroKeys));
  1732.  
  1733.                                         if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
  1734.                                             Success = TRUE;
  1735.                                     }
  1736.                                 }
  1737.                                 else
  1738.                                 {
  1739.                                     /* The file read pointer is positioned
  1740.                                      * just in front of the first data
  1741.                                      * to be read, so let's don't disappoint
  1742.                                      * iffparse and read it.
  1743.                                      */
  1744.  
  1745.                                     if(ReadChunkBytes(Handle,Keys,sizeof(struct MacroKeys)) == sizeof(struct MacroKeys))
  1746.                                         Success = TRUE;
  1747.                                 }
  1748.                             }
  1749.                             else
  1750.                             {
  1751.                                     /* File was created by WriteIFFData previous
  1752.                                      * to revision 1.4.
  1753.                                      */
  1754.  
  1755.                                 memset(Keys,0,sizeof(struct MacroKeys));
  1756.  
  1757.                                 if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
  1758.                                     Success = TRUE;
  1759.                             }
  1760.                         }
  1761.                     }
  1762.                 }
  1763.  
  1764.                 CloseIFF(Handle);
  1765.             }
  1766.  
  1767.             Close(Handle -> iff_Stream);
  1768.         }
  1769.  
  1770.         FreeIFF(Handle);
  1771.     }
  1772.  
  1773.     return(Success);
  1774. }
  1775.  
  1776.     /* FindThisItem(ULONG MenuID):
  1777.      *
  1778.      *    Scan the main menu for a menuitem associated with a
  1779.      *    menu ID.
  1780.      */
  1781.  
  1782. struct MenuItem *
  1783. FindThisItem(ULONG MenuID)
  1784. {
  1785.     struct Menu    *FirstMenu;
  1786.     struct MenuItem    *FirstItem;
  1787.  
  1788.     FirstMenu = Menu;
  1789.  
  1790.     while(FirstMenu)
  1791.     {
  1792.         FirstItem = FirstMenu -> FirstItem;
  1793.  
  1794.         while(FirstItem)
  1795.         {
  1796.             if((ULONG)GTMENUITEM_USERDATA(FirstItem) == MenuID)
  1797.                 return(FirstItem);
  1798.             else
  1799.                 FirstItem = FirstItem -> NextItem;
  1800.         }
  1801.  
  1802.         FirstMenu = FirstMenu -> NextMenu;
  1803.     }
  1804.  
  1805.     return(NULL);
  1806. }
  1807.  
  1808.     /* GetFileSize(UBYTE *Name):
  1809.      *
  1810.      *    Simple routine to return the size of a file in
  1811.      *    bytes.
  1812.      */
  1813.  
  1814. LONG
  1815. GetFileSize(UBYTE *Name)
  1816. {
  1817.     struct FileInfoBlock __aligned    FileInfo;
  1818.     BPTR                FileLock;
  1819.     LONG                FileSize = 0;
  1820.  
  1821.     if(FileLock = Lock(Name,ACCESS_READ))
  1822.     {
  1823.         if(Examine(FileLock,&FileInfo))
  1824.             FileSize = FileInfo . fib_Size;
  1825.  
  1826.         UnLock(FileLock);
  1827.     }
  1828.  
  1829.     return(FileSize);
  1830. }
  1831.  
  1832.     /* GetFile(UBYTE *Title,UBYTE *Directory,UBYTE *Name,UBYTE *Buffer,UBYTE *Pattern,BYTE SaveFlag,BYTE MultiSelect):
  1833.      *
  1834.      *    Call the asl.library file requester to select a single or
  1835.      *    a couple of files.
  1836.      */
  1837.  
  1838. struct FileRequester *
  1839. GetFile(UBYTE *Title,UBYTE *Directory,UBYTE *Name,UBYTE *Buffer,UBYTE *Pattern,BYTE SaveFlag,BYTE MultiSelect,BYTE DirsOnly,UBYTE *OKText)
  1840. {
  1841.     struct FileRequester    *AslFileRequest;
  1842.     BYTE             Result        = FALSE,
  1843.                  DefaultPattern    = FALSE;
  1844.     LONG             Flags,ExtFlags = 0;
  1845.     WORD             i,j;
  1846.  
  1847.     STATIC UBYTE         DirBuffer[256],
  1848.                  PatternBuffer[256],
  1849.                  OtherTitle[40];
  1850.  
  1851.         /* We use this tag array to remember the size and
  1852.          * position of the asl requester window.
  1853.          */
  1854.  
  1855.     STATIC struct {
  1856.         ULONG Tag1,    LeftEdge;
  1857.         ULONG Tag2,    TopEdge;
  1858.         ULONG Tag3,    Width;
  1859.         ULONG Tag4,    Height;
  1860.         ULONG Tag5;
  1861.     } Dims = {
  1862.         ASL_LeftEdge,    -1,
  1863.         ASL_TopEdge,    -1,
  1864.         ASL_Width,    -1,
  1865.         ASL_Height,    -1,
  1866.  
  1867.         TAG_DONE
  1868.     };
  1869.  
  1870.     for(i = j = 0 ; i < strlen(Title) ; i++)
  1871.     {
  1872.         if(Title[i] != '_')
  1873.             OtherTitle[j++] = Title[i];
  1874.     }
  1875.  
  1876.     OtherTitle[j] = 0;
  1877.  
  1878.     Title = OtherTitle;
  1879.  
  1880.     if(DirsOnly)
  1881.     {
  1882.         ExtFlags |= FIL1F_NOFILES;
  1883.  
  1884.         if(Pattern)
  1885.             ExtFlags |= FIL1F_MATCHDIRS;
  1886.     }
  1887.  
  1888.         /* Empty directory string? Revert to the last directory
  1889.          * name.
  1890.          */
  1891.  
  1892.     if(!Directory[0])
  1893.     {
  1894.         if(!DirBuffer[0])
  1895.         {
  1896.             if(!GetCurrentDirName(DirBuffer,256))
  1897.                 DirBuffer[0] = 0;
  1898.         }
  1899.  
  1900.         Directory = DirBuffer;
  1901.     }
  1902.  
  1903.         /* If a wildcard pattern is required, add a gadget
  1904.          * to display it.
  1905.          */
  1906.  
  1907.     if(Pattern)
  1908.     {
  1909.         Flags = FILF_PATGAD;
  1910.  
  1911.         if(!Pattern[0])
  1912.         {
  1913.             DefaultPattern = TRUE;
  1914.  
  1915.             if(PatternBuffer[0])
  1916.                 Pattern = PatternBuffer;
  1917.             else
  1918.                 Pattern = "#?";
  1919.         }
  1920.         else
  1921.         {
  1922.             if(!strcmp(Pattern,"#?") || !Stricmp(Pattern,PatternBuffer))
  1923.             {
  1924.                 DefaultPattern = TRUE;
  1925.  
  1926.                 Pattern = PatternBuffer;
  1927.             }
  1928.         }
  1929.     }
  1930.     else
  1931.     {
  1932.         Flags = 0;
  1933.  
  1934.         Pattern = "#?";
  1935.     }
  1936.  
  1937.         /* Set the save flag if we are about to save something. */
  1938.  
  1939.     if(SaveFlag)
  1940.         Flags |= FILF_SAVE;
  1941.  
  1942.         /* Set the multiselect bit if multiple files are
  1943.          * to be selected (e.g. for batch file upload).
  1944.          */
  1945.  
  1946.     if(MultiSelect)
  1947.         Flags |= FILF_MULTISELECT;
  1948.  
  1949.         /* Provide a standard `Ok' text if none
  1950.          * specified.
  1951.          */
  1952.  
  1953.     if(!OKText)
  1954.         OKText = (SaveFlag ? LocaleString(MSG_GLOBAL_SAVE_TXT) : LocaleString(MSG_GLOBAL_OPEN_TXT));
  1955.  
  1956.         /* Allocate the asl.library directory requester
  1957.          * and display it.
  1958.          */
  1959.  
  1960.     if(AslFileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  1961.         ASL_Window,    Window,
  1962.         ASL_File,    Name,
  1963.         ASL_Dir,    Directory,
  1964.         ASL_Hail,    Title,
  1965.         ASL_FuncFlags,    Flags | FILF_NEWIDCMP,
  1966.         ASL_Pattern,    Pattern,
  1967.         ASL_OKText,    OKText,
  1968.         ASL_ExtFlags1,    ExtFlags,
  1969. #ifdef ASLSM_FilterFunc
  1970.         ASLFR_TextAttr,    &DefaultFont,
  1971. #endif    /* ASLSM_FilterFunc */
  1972.         (Dims . LeftEdge == -1) ? TAG_DONE : TAG_MORE,&Dims))
  1973.     {
  1974.         if(AslRequestTags(AslFileRequest,TAG_DONE))
  1975.         {
  1976.             Dims . LeftEdge    = AslFileRequest -> rf_LeftEdge;
  1977.             Dims . TopEdge    = AslFileRequest -> rf_TopEdge;
  1978.             Dims . Width    = AslFileRequest -> rf_Width;
  1979.             Dims . Height    = AslFileRequest -> rf_Height;
  1980.  
  1981.             if(!DirsOnly)
  1982.             {
  1983.                     /* Do we have a valid file name? */
  1984.  
  1985.                 if(AslFileRequest -> rf_File[0])
  1986.                 {
  1987.                         /* Build a legal path/file string. */
  1988.  
  1989.                     strcpy(Buffer,AslFileRequest -> rf_Dir);
  1990.  
  1991.                     AddPart((UBYTE *)Buffer,(UBYTE *)AslFileRequest -> rf_File,256);
  1992.  
  1993.                     Result = TRUE;
  1994.  
  1995.                     strcpy(DirBuffer,AslFileRequest -> rf_Dir);
  1996.                 }
  1997.             }
  1998.             else
  1999.             {
  2000.                 if(AslFileRequest -> rf_Dir[0])
  2001.                 {
  2002.                     strcpy(Buffer,AslFileRequest -> rf_Dir);
  2003.  
  2004.                     Result = TRUE;
  2005.  
  2006.                     strcpy(DirBuffer,AslFileRequest -> rf_Dir);
  2007.                 }
  2008.             }
  2009.         }
  2010.     }
  2011.  
  2012.         /* We didn't get a file, no need to keep the
  2013.          * file requester.
  2014.          */
  2015.  
  2016.     if(!Result && AslFileRequest)
  2017.     {
  2018.         FreeAslRequest(AslFileRequest);
  2019.  
  2020.         return(NULL);
  2021.     }
  2022.     else
  2023.     {
  2024.         if(DefaultPattern)
  2025.             strcpy(PatternBuffer,AslFileRequest -> rf_Pat);
  2026.  
  2027.         return(AslFileRequest);
  2028.     }
  2029. }
  2030.  
  2031.     /* MyEasyRequest(struct Window *Window,UBYTE *Text,UBYTE *Gadgets,...):
  2032.      *
  2033.      *    Really quite simple varargs version of Intuition's
  2034.      *    EasyRequest requester.
  2035.      */
  2036.  
  2037. WORD __stdargs
  2038. MyEasyRequest(struct Window *Window,UBYTE *Text,UBYTE *Gadgets,...)
  2039. {
  2040.     struct EasyStruct    Easy;
  2041.     WORD            Result;
  2042.     ULONG            IDCMP = NULL;
  2043.     va_list             VarArgs;
  2044.  
  2045.         /* Standard data. */
  2046.  
  2047.     Easy . es_StructSize    = sizeof(struct EasyStruct);
  2048.     Easy . es_Flags        = NULL;
  2049.     Easy . es_Title        = (UBYTE *)LocaleString(MSG_TERMAUX_TERM_REQUEST_TXT);
  2050.     Easy . es_TextFormat    = (UBYTE *)Text;
  2051.     Easy . es_GadgetFormat    = (UBYTE *)Gadgets;
  2052.  
  2053.         /* Use the argument array to build the
  2054.          * requester and display it.
  2055.          */
  2056.  
  2057.     va_start(VarArgs,Gadgets);
  2058.     Result = EasyRequestArgs(Window,&Easy,&IDCMP,VarArgs);
  2059.     va_end(VarArgs);
  2060.  
  2061.     return(Result);
  2062. }
  2063.  
  2064.     /* SelectTime():
  2065.      *
  2066.      *    Searches for the correct unit/pay conversion values.
  2067.      */
  2068.  
  2069. VOID
  2070. SelectTime(struct PhoneEntry *SomeEntry)
  2071. {
  2072.     struct TimeDateNode        *TimeDateNode;
  2073.     struct DateStamp __aligned     Date;
  2074.     struct ClockData         ClockData;
  2075.     BYTE                 FoundOne = FALSE;
  2076.  
  2077.         /* Obtain current time and date. */
  2078.  
  2079.     DateStamp(&Date);
  2080.  
  2081.         /* Convert into a more suitable form (note: seconds are
  2082.          * required as an input value).
  2083.          */
  2084.  
  2085.     Amiga2Date(Date . ds_Days * 86400 + Date . ds_Minute * 60 + Date . ds_Tick / TICKS_PER_SECOND,&ClockData);
  2086.  
  2087.         /* Apparently, in the US the week starts with Sunday, we'll
  2088.          * wrap the week around to let it start with Monday.
  2089.          */
  2090.  
  2091.     if(ClockData . wday)
  2092.         ClockData . wday--;
  2093.     else
  2094.         ClockData . wday = 6;
  2095.  
  2096.         /* Change the month, too... */
  2097.  
  2098.     ClockData . month--;
  2099.  
  2100.         /* First step: search for current day. */
  2101.  
  2102.     TimeDateNode = (struct TimeDateNode *)SomeEntry -> TimeDateList . mlh_Head;
  2103.  
  2104.         /* Skip first entry. */
  2105.  
  2106.     TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
  2107.  
  2108.     while(TimeDateNode -> VanillaNode . ln_Succ)
  2109.     {
  2110.             /* Does it match a specific date? */
  2111.  
  2112.         if(TimeDateNode -> TimeDate . Month == ClockData . month && TimeDateNode -> TimeDate . Day == ClockData . mday)
  2113.         {
  2114.             FoundOne = TRUE;
  2115.  
  2116.             break;
  2117.         }
  2118.  
  2119.         TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
  2120.     }
  2121.  
  2122.         /* Second step: search for week day settings. */
  2123.  
  2124.     if(!FoundOne)
  2125.     {
  2126.         TimeDateNode = (struct TimeDateNode *)SomeEntry -> TimeDateList . mlh_Head;
  2127.  
  2128.             /* Skip first entry. */
  2129.  
  2130.         TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
  2131.  
  2132.         while(TimeDateNode -> VanillaNode . ln_Succ)
  2133.         {
  2134.                 /* Does it match a specific day? */
  2135.  
  2136.             if(TimeDateNode -> TimeDate . Month == -1 && (TimeDateNode -> TimeDate . Day & (1 << ClockData . wday)))
  2137.             {
  2138.                 FoundOne = TRUE;
  2139.  
  2140.                 break;
  2141.             }
  2142.  
  2143.             TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
  2144.         }
  2145.     }
  2146.  
  2147.         /* Third step: use default settings. */
  2148.  
  2149.     if(!FoundOne)
  2150.         TimeDateNode = (struct TimeDateNode *)SomeEntry -> TimeDateList . mlh_Head;
  2151.  
  2152.         /* Fill in the remaining data. */
  2153.  
  2154.     PayPerUnit[0]    = TimeDateNode -> TimeDate . PayPerUnit[0];
  2155.     PayPerUnit[1]    = TimeDateNode -> TimeDate . PayPerUnit[1];
  2156.  
  2157.     SecPerUnit[0]    = TimeDateNode -> TimeDate . SecPerUnit[0];
  2158.     SecPerUnit[1]    = TimeDateNode -> TimeDate . SecPerUnit[1];
  2159.  
  2160.     TimeOfDay[0]    = TimeDateNode -> TimeDate . TimeOfDay[0];
  2161.     TimeOfDay[1]    = TimeDateNode -> TimeDate . TimeOfDay[1];
  2162. }
  2163.  
  2164.     /* Raise(UWORD Colour):
  2165.      *
  2166.      *    Make an RGB value brighter.
  2167.      */
  2168.  
  2169. STATIC UWORD __regargs
  2170. Raise(UWORD Colour)
  2171. {
  2172.     WORD r,g,b;
  2173.  
  2174.     r =  (Colour >> 8)        + 4;
  2175.     g = ((Colour >> 4) & 0xF) + 4;
  2176.     b = ((Colour     ) & 0xF) + 4;
  2177.  
  2178.     if(r > 15)
  2179.         r = 15;
  2180.  
  2181.     if(g > 15)
  2182.         g = 15;
  2183.  
  2184.     if(b > 15)
  2185.         b = 15;
  2186.  
  2187.     return(r << 8 | g << 4 | b);
  2188. }
  2189.  
  2190.     /* VisualBeep():
  2191.      *
  2192.      *    Handle the visual part of the display beep.
  2193.      */
  2194.  
  2195. STATIC BYTE
  2196. VisualBeep()
  2197. {
  2198.     struct UCopList    *UserCopperList;
  2199.  
  2200.         /* Create a user copper list. */
  2201.  
  2202.     if(UserCopperList = (struct UCopList *)AllocMem(sizeof(struct UCopList),MEMF_ANY|MEMF_CLEAR))
  2203.     {
  2204.             /* Initialize for 35 commands. */
  2205.  
  2206.         if(UCopperListInit(UserCopperList,1 + 16 + 1 + 16 + 1))
  2207.         {
  2208.             WORD i;
  2209.  
  2210.                 /* Wait until first line of window. */
  2211.  
  2212.             CWAIT(UserCopperList,Window -> TopEdge,0);
  2213.  
  2214.                 /* Set the light colours. */
  2215.  
  2216.             for(i = 0 ; i < 16 ; i++)
  2217.                 CMOVE(UserCopperList,custom . color[i],Raise(GetRGB4(Screen -> ViewPort . ColorMap,i)));
  2218.  
  2219.                 /* Wait until bottom of window. */
  2220.  
  2221.             CWAIT(UserCopperList,Window -> TopEdge + Window -> Height - 1,0);
  2222.  
  2223.                 /* Set the standard colours. */
  2224.  
  2225.             for(i = 0 ; i < 16 ; i++)
  2226.                 CMOVE(UserCopperList,custom . color[i],GetRGB4(Screen -> ViewPort . ColorMap,i));
  2227.  
  2228.                 /* Finish list. */
  2229.  
  2230.             CEND(UserCopperList);
  2231.  
  2232.                 /* Install user copper list... */
  2233.  
  2234.             Screen -> ViewPort . UCopIns = UserCopperList;
  2235.  
  2236.                 /* ...and display it. */
  2237.  
  2238.             RethinkDisplay();
  2239.  
  2240.             return(TRUE);
  2241.         }
  2242.         else
  2243.             FreeMem(UserCopperList,sizeof(struct UCopList));
  2244.     }
  2245.  
  2246.     return(FALSE);
  2247. }
  2248.  
  2249.     /* PrintStatusLine(struct RastPort *RPort,STRPTR String):
  2250.      *
  2251.      *    Print a string into the status line,
  2252.      *    checks first to see if the Text() routine is
  2253.      *    likely to wait.
  2254.      */
  2255.  
  2256. STATIC VOID __regargs
  2257. PrintStatusLine(struct RastPort *RPort,STRPTR String)
  2258. {
  2259.     if(AttemptLockLayerRom(RPort -> Layer))
  2260.     {
  2261.         Text(RPort,String,strlen(String));
  2262.  
  2263.         UnlockLayerRom(RPort -> Layer);
  2264.     }
  2265. }
  2266.  
  2267.     /* StatusServer():
  2268.      *
  2269.      *    Asynchronous process to continuosly display the current
  2270.      *    terminal settings.
  2271.      */
  2272.  
  2273. VOID __saveds
  2274. StatusServer()
  2275. {
  2276.     STATIC struct timeval     OnlineTime;
  2277.     STATIC UBYTE         OnlineBuffer[20];
  2278.     STATIC BYTE         GotOnline        = FALSE,
  2279.                  WasOnline        = FALSE,
  2280.                  ShowPay        = FALSE,
  2281.                  FlagBit        = FALSE;
  2282.     STATIC LONG         SecCount        = 0,
  2283.                  BeepCount        = 0;
  2284.  
  2285.     struct RastPort        *RPort;
  2286.     UBYTE             Buffer[80];
  2287.  
  2288.     struct timerequest    *TimeRequest;
  2289.     struct MsgPort        *TimePort;
  2290.  
  2291.     BYTE             Background        = FALSE,
  2292.                  FlashIt        = FALSE,
  2293.                  SetColours        = FALSE,
  2294.                  StandardColours    = TRUE,
  2295.                  KeepGoing        = TRUE,
  2296.                  Beeping        = FALSE;
  2297.  
  2298.     BYTE             LastProtocol[40],
  2299.                  ProtocolBuffer[20],
  2300.                  i;
  2301.  
  2302.     BYTE             LastFont        = -1,
  2303.                  LastEmulation        = -1,
  2304.                  LastBitsPerChar    = -1,
  2305.                  LastParity        = -1,
  2306.                  LastStopBits        = -1,
  2307.                  LastStatus        = -1;
  2308.  
  2309.     LONG             LastBaud        = -1;
  2310.  
  2311.     LONG             ThisHour,ThisMinute,TestTime;
  2312.  
  2313.     LastProtocol[0] = 0;
  2314.  
  2315.     LocalizeString(ConfigEmulation,MSG_TERMAUX_ANSI_VT102_TXT,MSG_TERMAUX_EXTERNAL_TXT);
  2316.     LocalizeString(ConfigParity,MSG_TERMAUX_NONE_TXT,MSG_TERMAUX_SPACE_TXT);
  2317.     LocalizeString(ConfigStatus,MSG_TERMAUX_READY_TXT,MSG_TERMAUX_HANG_UP_TXT);
  2318.  
  2319.         /* Create a timer device request. */
  2320.  
  2321.     if(TimePort = (struct MsgPort *)CreateMsgPort())
  2322.     {
  2323.         if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  2324.         {
  2325.             if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,0))
  2326.             {
  2327.                     /* Signal our father process
  2328.                      * that we're running.
  2329.                      */
  2330.  
  2331.                 Signal(ThisProcess,SIGBREAKF_CTRL_C);
  2332.  
  2333.                 if(StatusWindow)
  2334.                 {
  2335.                     RPort = StatusWindow -> RPort;
  2336.  
  2337.                     if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2338.                     {
  2339.                         MoveSingle(0);
  2340.  
  2341.                         Text(RPort,"        ·            ·            ·         ·       ·          · 00:00:00",73);
  2342.                     }
  2343.                     else
  2344.                     {
  2345.                         MoveItem(64,1);
  2346.  
  2347.                         Text(RPort,"00:00:00",8);
  2348.                     }
  2349.                 }
  2350.                 else
  2351.                     RPort = NULL;
  2352.  
  2353.                     /* Keep on displaying. */
  2354.  
  2355.                 while(KeepGoing)
  2356.                 {
  2357.                         /* Are we to quit? */
  2358.  
  2359.                     if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
  2360.                     {
  2361.                         KeepGoing = FALSE;
  2362.  
  2363.                         SetSignal(0,SIGBREAKF_CTRL_C);
  2364.                     }
  2365.  
  2366.                         /* Get the current time. */
  2367.  
  2368.                     TimeRequest -> tr_node . io_Command = TR_GETSYSTIME;
  2369.  
  2370.                     DoIO(TimeRequest);
  2371.  
  2372.                         /* A connection has just
  2373.                          * been established.
  2374.                          */
  2375.  
  2376.                     if(Online && !GotOnline)
  2377.                     {
  2378.                         OnlineTime = TimeRequest -> tr_time;
  2379.  
  2380.                         GotOnline = TRUE;
  2381.  
  2382.                         SecCount = 0;
  2383.  
  2384.                         FlagBit = FALSE;
  2385.                     }
  2386.  
  2387.                         /* Print the current time. */
  2388.  
  2389.                     ThisHour    = (TimeRequest -> tr_time . tv_secs % 86400) / 3600;
  2390.                     ThisMinute    = (TimeRequest -> tr_time . tv_secs % 3600) / 60;
  2391.  
  2392.                     if(RPort)
  2393.                     {
  2394.                         SPrintf(Buffer,"%02ld:%02ld:%02ld",ThisHour,ThisMinute,TimeRequest -> tr_time . tv_secs % 60);
  2395.  
  2396.                         if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2397.                             MoveSingle(54);
  2398.                         else
  2399.                             MoveItem(64,0);
  2400.  
  2401.                         PrintStatusLine(RPort,Buffer);
  2402.                     }
  2403.  
  2404.                     if(Online)
  2405.                     {
  2406.                         STATIC struct timeval    LastTime;
  2407.                         struct timeval        TempTime;
  2408.  
  2409.                         WasOnline = TRUE;
  2410.  
  2411.                         if(ChosenEntry)
  2412.                         {
  2413.                             if(!(ThisMinute % 10) && !(TimeRequest -> tr_time . tv_secs % 60))
  2414.                             {
  2415.                                 ChosenInUse = TRUE;
  2416.  
  2417.                                 SelectTime(ChosenEntry);
  2418.  
  2419.                                 ChosenInUse = FALSE;
  2420.                             }
  2421.  
  2422.                             TestTime = ThisHour * 6 + ThisMinute / 10;
  2423.  
  2424.                             if(TestTime >= TimeOfDay[0] && TestTime <= TimeOfDay[1])
  2425.                                 PreferredTime = 0;
  2426.                             else
  2427.                             {
  2428.                                 if(TestTime >= TimeOfDay[1] && TestTime <= TimeOfDay[0])
  2429.                                     PreferredTime = 1;
  2430.                                 else
  2431.                                 {
  2432.                                     if(TestTime >= TimeOfDay[0] && TestTime >= TimeOfDay[1])
  2433.                                     {
  2434.                                         if(TimeOfDay[0] > TimeOfDay[1])
  2435.                                             PreferredTime = 0;
  2436.                                         else
  2437.                                             PreferredTime = 1;
  2438.                                     }
  2439.                                     else
  2440.                                     {
  2441.                                         if(TestTime <= TimeOfDay[0] && TestTime <= TimeOfDay[1])
  2442.                                         {
  2443.                                             if(TimeOfDay[0] > TimeOfDay[1])
  2444.                                                 PreferredTime = 0;
  2445.                                             else
  2446.                                                 PreferredTime = 1;
  2447.                                         }
  2448.                                     }
  2449.                                 }
  2450.                             }
  2451.  
  2452.                             if(!CurrentPay)
  2453.                                 CurrentPay = PayPerUnit[PreferredTime];
  2454.  
  2455.                             FlagBit ^= TRUE;
  2456.  
  2457.                             if(!FlagBit)
  2458.                             {
  2459.                                 if(SecPerUnit[PreferredTime])
  2460.                                 {
  2461.                                     if(SecCount == SecPerUnit[PreferredTime])
  2462.                                     {
  2463.                                         SecCount = 0;
  2464.  
  2465.                                         CurrentPay += PayPerUnit[PreferredTime];
  2466.                                     }
  2467.                                 }
  2468.  
  2469.                                 SecCount++;
  2470.                             }
  2471.                         }
  2472.  
  2473.                             /* Show the time
  2474.                              * we have been online
  2475.                              * yet.
  2476.                              */
  2477.  
  2478.                         TempTime = TimeRequest -> tr_time;
  2479.  
  2480.                         if(TempTime . tv_secs != LastTime . tv_secs)
  2481.                         {
  2482.                             LastTime = TempTime;
  2483.  
  2484.                             SubTime(&TempTime,&OnlineTime);
  2485.  
  2486.                             if(!(TempTime . tv_secs % 5) && TempTime . tv_secs)
  2487.                                 ShowPay ^= TRUE;
  2488.  
  2489.                             SPrintf(OnlineBuffer,"%02ld:%02ld:%02ld",(TempTime . tv_secs % 86400) / 3600,(TempTime . tv_secs % 3600) / 60,TempTime . tv_secs % 60);
  2490.  
  2491.                             if(ShowPay && CurrentPay && ChosenEntry)
  2492.                             {
  2493.                                 SPrintf(Buffer,"%s          ",CreateSum(CurrentPay,FALSE));
  2494.  
  2495.                                 Buffer[8] = 0;
  2496.                             }
  2497.                             else
  2498.                                 strcpy(Buffer,OnlineBuffer);
  2499.  
  2500.                             if(RPort)
  2501.                             {
  2502.                                 if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2503.                                     MoveSingle(65);
  2504.                                 else
  2505.                                     MoveItem(64,1);
  2506.  
  2507.                                 PrintStatusLine(RPort,Buffer);
  2508.                             }
  2509.                         }
  2510.                     }
  2511.                     else
  2512.                     {
  2513.                         if(WasOnline)
  2514.                         {
  2515.                             WasOnline = FALSE;
  2516.  
  2517.                             if(RPort)
  2518.                             {
  2519.                                 if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2520.                                     MoveSingle(65);
  2521.                                 else
  2522.                                     MoveItem(64,1);
  2523.  
  2524.                                 PrintStatusLine(RPort,OnlineBuffer);
  2525.                             }
  2526.                         }
  2527.  
  2528.                         if(GotOnline)
  2529.                             GotOnline = FALSE;
  2530.                     }
  2531.  
  2532.                         /* Take care of the visual beep
  2533.                          * if enabled.
  2534.                          */
  2535.  
  2536.                     if(Beeping)
  2537.                     {
  2538.                         if(!(BeepCount--))
  2539.                         {
  2540.                             Beeping = FALSE;
  2541.  
  2542.                                 /* Remove the copper list. */
  2543.  
  2544.                             FreeVPortCopLists(&Screen -> ViewPort);
  2545.  
  2546.                                 /* Really remove it. */
  2547.  
  2548.                             RemakeDisplay();
  2549.  
  2550.                                 /* Clear the signal bit. */
  2551.  
  2552.                             SetSignal(0,SIGBREAKF_CTRL_D);
  2553.                         }
  2554.                     }
  2555.  
  2556.                         /* Are we to show a visual beep? */
  2557.  
  2558.                     if(SetSignal(0,0) & SIGBREAKF_CTRL_D)
  2559.                     {
  2560.                         if(Config . SystemBeep)
  2561.                         {
  2562.                             DisplayBeep(Screen);
  2563.  
  2564.                             SetSignal(0,SIGBREAKF_CTRL_D);
  2565.                         }
  2566.                         else
  2567.                         {
  2568.                             if(!Beeping)
  2569.                             {
  2570.                                 if(VisualBeep())
  2571.                                 {
  2572.                                     Beeping = TRUE;
  2573.  
  2574.                                     BeepCount = 1;
  2575.  
  2576.                                     SetSignal(0,SIGBREAKF_CTRL_D);
  2577.                                 }
  2578.                             }
  2579.                         }
  2580.                     }
  2581.  
  2582.                         /* Display the current terminal
  2583.                          * status.
  2584.                          */
  2585.  
  2586.                     if(LastStatus != Status)
  2587.                     {
  2588.                         LastStatus = Status;
  2589.  
  2590.                         if(RPort)
  2591.                         {
  2592.                             if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2593.                                 MoveSingle(0);
  2594.                             else
  2595.                                 MoveItem(7,0);
  2596.  
  2597.                             PrintStatusLine(RPort,ConfigStatus[LastStatus]);
  2598.                         }
  2599.                     }
  2600.  
  2601.                         /* Show the current transfer
  2602.                          * protocol.
  2603.                          */
  2604.  
  2605.                     if(strcmp(LastProtocol,FilePart(Config . Protocol)))
  2606.                     {
  2607.                         strcpy(LastProtocol,FilePart(Config . Protocol));
  2608.  
  2609.                         strcpy(ProtocolBuffer,"        ");
  2610.  
  2611.                         for(i = 0 ; i < 8 ; i++)
  2612.                         {
  2613.                             if(!LastProtocol[i + 3] || LastProtocol[i + 3] == '.')
  2614.                                 break;
  2615.                             else
  2616.                                 ProtocolBuffer[i] = LastProtocol[i + 3];
  2617.                         }
  2618.  
  2619.                         if(RPort)
  2620.                         {
  2621.                             if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2622.                                 MoveSingle(23);
  2623.                             else
  2624.                                 MoveItem(25,0);
  2625.  
  2626.                             PrintStatusLine(RPort,ProtocolBuffer);
  2627.                         }
  2628.                     }
  2629.  
  2630.                         /* Show the current baud
  2631.                          * rate.
  2632.                          */
  2633.  
  2634.                     if(LastBaud != Config . BaudRate)
  2635.                     {
  2636.                         LastBaud = Config . BaudRate;
  2637.  
  2638.                         if(RPort)
  2639.                         {
  2640.                             extern APTR LocaleBase;
  2641.  
  2642.                             if(LocaleBase)
  2643.                                 SPrintf(Buffer,"%lD        ",LastBaud);
  2644.                             else
  2645.                                 SPrintf(Buffer,"%ld        ",LastBaud);
  2646.  
  2647.                             Buffer[7] = 0;
  2648.  
  2649.                             if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2650.                                 MoveSingle(36);
  2651.                             else
  2652.                                 MoveItem(47,0);
  2653.  
  2654.                             PrintStatusLine(RPort,Buffer);
  2655.                         }
  2656.                     }
  2657.  
  2658.                         /* Show the current
  2659.                          * terminal font.
  2660.                          */
  2661.  
  2662.                     if(LastFont != Config . Font)
  2663.                     {
  2664.                         LastFont = Config . Font;
  2665.  
  2666.                         if(RPort)
  2667.                         {
  2668.                             if(Config . StatusLine != STATUSLINE_COMPRESSED)
  2669.                             {
  2670.                                 MoveItem(7,1);
  2671.  
  2672.                                 PrintStatusLine(RPort,ConfigFont[LastFont]);
  2673.                             }
  2674.                         }
  2675.                     }
  2676.  
  2677.                         /* Show the current terminal
  2678.                          * emulation.
  2679.                          */
  2680.  
  2681.                     if(Config . Emulation == 3)
  2682.                     {
  2683.                         LastEmulation = Config . Emulation;
  2684.  
  2685.                         if(RPort)
  2686.                         {
  2687.                             SPrintf(Buffer,"%s         ",EmulationName);
  2688.  
  2689.                             Buffer[10] = 0;
  2690.  
  2691.                             if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2692.                                 MoveSingle(10);
  2693.                             else
  2694.                                 MoveItem(25,1);
  2695.  
  2696.                             PrintStatusLine(RPort,Buffer);
  2697.                         }
  2698.                     }
  2699.                     else
  2700.                     {
  2701.                         if(LastEmulation != Config . Emulation)
  2702.                         {
  2703.                             LastEmulation = Config . Emulation;
  2704.  
  2705.                             if(RPort)
  2706.                             {
  2707.                                 if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2708.                                     MoveSingle(10);
  2709.                                 else
  2710.                                     MoveItem(25,1);
  2711.  
  2712.                                 PrintStatusLine(RPort,ConfigEmulation[LastEmulation]);
  2713.                             }
  2714.                         }
  2715.                     }
  2716.  
  2717.                         /* Show the current serial
  2718.                          * parameters (parity, etc).
  2719.                          */
  2720.  
  2721.                     if(LastBitsPerChar != Config . BitsPerChar || LastParity != Config . Parity || LastStopBits != Config . StopBits)
  2722.                     {
  2723.                         LastBitsPerChar    = Config . BitsPerChar;
  2724.                         LastParity    = Config . Parity;
  2725.                         LastStopBits    = Config . StopBits;
  2726.  
  2727.                         if(RPort)
  2728.                         {
  2729.                             if(Config . StatusLine == STATUSLINE_COMPRESSED)
  2730.                             {
  2731.                                 STATIC UBYTE Parities[] =
  2732.                                 {
  2733.                                     'N','E','O','M','S'
  2734.                                 };
  2735.  
  2736.                                 MoveSingle(46);
  2737.  
  2738.                                 SPrintf(Buffer,"%ld-%lc-%ld",LastBitsPerChar,Parities[LastParity],LastStopBits);
  2739.                             }
  2740.                             else
  2741.                             {
  2742.                                 SPrintf(Buffer,"%ld-%s-%ld   ",LastBitsPerChar,ConfigParity[LastParity],LastStopBits);
  2743.  
  2744.                                 Buffer[9] = 0;
  2745.  
  2746.                                 MoveItem(47,1);
  2747.                             }
  2748.  
  2749.                             PrintStatusLine(RPort,Buffer);
  2750.                         }
  2751.                     }
  2752.  
  2753.                         /* Wait another half a second. */
  2754.  
  2755.                     if(KeepGoing)
  2756.                     {
  2757.                         ULONG Mask;
  2758.  
  2759.                         TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  2760.                         TimeRequest -> tr_time . tv_secs    = 0;
  2761.                         TimeRequest -> tr_time . tv_micro    = MILLION / 2;
  2762.  
  2763.                         SendIO(TimeRequest);
  2764.  
  2765.                         FOREVER
  2766.                         {
  2767.                             Mask = Wait(SIGBREAKF_CTRL_D | (1 << TimePort -> mp_SigBit));
  2768.  
  2769.                             if(Mask & SIGBREAKF_CTRL_D)
  2770.                             {
  2771.                                 if(Config . SystemBeep)
  2772.                                 {
  2773.                                     DisplayBeep(Screen);
  2774.  
  2775.                                     SetSignal(0,SIGBREAKF_CTRL_D);
  2776.                                 }
  2777.                                 else
  2778.                                 {
  2779.                                     if(!Beeping)
  2780.                                     {
  2781.                                         if(VisualBeep())
  2782.                                         {
  2783.                                             Beeping = TRUE;
  2784.  
  2785.                                             BeepCount = 1;
  2786.                                         }
  2787.                                     }
  2788.                                 }
  2789.                             }
  2790.  
  2791.                             if(Mask & (1 << TimePort -> mp_SigBit))
  2792.                             {
  2793.                                 WaitIO(TimeRequest);
  2794.  
  2795.                                 break;
  2796.                             }
  2797.                         }
  2798.                     }
  2799.  
  2800.                         /* Make the colours blink. */
  2801.  
  2802.                     if(Screen == IntuitionBase -> FirstScreen)
  2803.                     {
  2804.                             /* No main screen window active? */
  2805.  
  2806.                         if(StatusWindow)
  2807.                         {
  2808.                             if(!(Window -> Flags & WFLG_WINDOWACTIVE) && !(StatusWindow -> Flags & WFLG_WINDOWACTIVE))
  2809.                                 StandardColours = TRUE;
  2810.                         }
  2811.                         else
  2812.                         {
  2813.                             if(!(Window -> Flags & WFLG_WINDOWACTIVE))
  2814.                                 StandardColours = TRUE;
  2815.                         }
  2816.  
  2817.                             /* Menu button pressed or window disabled? */
  2818.  
  2819.                         if(Window -> Flags & (WFLG_MENUSTATE|WFLG_INREQUEST))
  2820.                             StandardColours = TRUE;
  2821.  
  2822.                         Background = FALSE;
  2823.                     }
  2824.                     else
  2825.                     {
  2826.                         if(!Background)
  2827.                             StandardColours = TRUE;
  2828.  
  2829.                         Background = TRUE;
  2830.                     }
  2831.  
  2832.                     if(StandardColours)
  2833.                     {
  2834.                         if(!SetColours)
  2835.                         {
  2836.                             LoadRGB4(VPort,Config . Colours,16);
  2837.  
  2838.                             SetColours = TRUE;
  2839.                         }
  2840.  
  2841.                         StandardColours = FlashIt = FALSE;
  2842.                     }
  2843.                     else
  2844.                     {
  2845.                             /* Are we to flash the display? */
  2846.  
  2847.                         if(!(Config . DisableBlinking & ~TERMINAL_FASTER))
  2848.                         {
  2849.                             if(Screen == IntuitionBase -> FirstScreen)
  2850.                             {
  2851.                                 if(FlashIt)
  2852.                                 {
  2853.                                     LoadRGB4(VPort,BlinkColours,16);
  2854.  
  2855.                                     SetColours = FALSE;
  2856.                                 }
  2857.                                 else
  2858.                                 {
  2859.                                     LoadRGB4(VPort,Config . Colours,16);
  2860.  
  2861.                                     SetColours = TRUE;
  2862.                                 }
  2863.                             }
  2864.  
  2865.                             FlashIt ^= TRUE;
  2866.                         }
  2867.                     }
  2868.                 }
  2869.  
  2870.                 CloseDevice(TimeRequest);
  2871.             }
  2872.  
  2873.             DeleteIORequest(TimeRequest);
  2874.         }
  2875.  
  2876.         DeleteMsgPort(TimePort);
  2877.     }
  2878.  
  2879.         /* Signal the father process that we're done
  2880.          * and quietly remove ourselves.
  2881.          */
  2882.  
  2883.     Forbid();
  2884.  
  2885.     Signal(ThisProcess,SIGBREAKF_CTRL_C);
  2886.  
  2887.     StatusProcess = NULL;
  2888. }
  2889.  
  2890.     /* CloseWindowSafely(struct Window *Window):
  2891.      *
  2892.      *    Close a window freeing all messages pending at
  2893.      *    its user port (taken from example source code
  2894.      *    published once upon a time in Amiga Mail).
  2895.      */
  2896.  
  2897. VOID
  2898. CloseWindowSafely(struct Window *Window)
  2899. {
  2900.     struct IntuiMessage    *IntuiMessage;
  2901.     struct Node        *Successor;
  2902.  
  2903.     Forbid();
  2904.  
  2905.     IntuiMessage = (struct IntuiMessage *)Window -> UserPort -> mp_MsgList . lh_Head;
  2906.  
  2907.     while(Successor = IntuiMessage -> ExecMessage . mn_Node . ln_Succ)
  2908.     {
  2909.         if(IntuiMessage -> IDCMPWindow == Window)
  2910.         {
  2911.             Remove(IntuiMessage);
  2912.  
  2913.             ReplyMsg((struct Message *)IntuiMessage);
  2914.         }
  2915.  
  2916.         IntuiMessage = (struct IntuiMessage *)Successor;
  2917.     }
  2918.  
  2919.     Window -> UserPort = NULL;
  2920.  
  2921.     ModifyIDCMP(Window,NULL);
  2922.  
  2923.     Permit();
  2924.  
  2925.     CloseWindow(Window);
  2926. }
  2927.  
  2928.     /* WaitTime(LONG Secs,LONG Micros):
  2929.      *
  2930.      *    Wait a given period of time.
  2931.      */
  2932.  
  2933. VOID
  2934. WaitTime(LONG Secs,LONG Micros)
  2935. {
  2936.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  2937.     TimeRequest -> tr_time . tv_secs    = Secs;
  2938.     TimeRequest -> tr_time . tv_micro    = Micros;
  2939.  
  2940.     DoIO(TimeRequest);
  2941. }
  2942.  
  2943.     /* GetEnvDOS(UBYTE *Name,UBYTE *Buffer):
  2944.      *
  2945.      *    Get the contents of a vanilla AmigaDOS environment
  2946.      *    variable.
  2947.      */
  2948.  
  2949. UBYTE *
  2950. GetEnvDOS(UBYTE *Name,UBYTE *Buffer)
  2951. {
  2952.     LONG    Size;
  2953.     BPTR    File,SomeLock;
  2954.  
  2955.     Buffer[0] = 0;
  2956.  
  2957.         /* Is ENV: present? */
  2958.  
  2959.     if(SomeLock = Lock("Env:",ACCESS_READ))
  2960.     {
  2961.         UBYTE SomeBuffer[80];
  2962.  
  2963.         UnLock(SomeLock);
  2964.  
  2965.         strcpy(SomeBuffer,"Env:");
  2966.         strcat(SomeBuffer,Name);
  2967.  
  2968.             /* Open the file. */
  2969.  
  2970.         if(File = Open(SomeBuffer,MODE_OLDFILE))
  2971.         {
  2972.                 /* Read the contents. */
  2973.  
  2974.             Size = Read(File,Buffer,256);
  2975.  
  2976.             Close(File);
  2977.  
  2978.             if(Size > 0)
  2979.             {
  2980.                 Buffer[Size] = 0;
  2981.  
  2982.                 return(Buffer);
  2983.             }
  2984.         }
  2985.     }
  2986.  
  2987.     return(NULL);
  2988. }
  2989.  
  2990.     /* SetEnvDOS(UBYTE *Name,UBYTE *Value):
  2991.      *
  2992.      *    Set the contents of a vanilla AmigaDOS environment
  2993.      *    variable.
  2994.      */
  2995.  
  2996. BYTE
  2997. SetEnvDOS(UBYTE *Name,UBYTE *Value)
  2998. {
  2999.     UBYTE    Buffer[80],*Destination;
  3000.     LONG    Length = 0;
  3001.     BPTR    File,FileLock;
  3002.     BYTE    Success = FALSE;
  3003.     WORD    i;
  3004.  
  3005.     for(i = 0 ; i < 2 ; i++)
  3006.     {
  3007.         if(i)
  3008.             Destination = "EnvArc:";
  3009.         else
  3010.             Destination = "Env:";
  3011.  
  3012.             /* Is ENV:/ENVARC: present? */
  3013.  
  3014.         if(FileLock = Lock(Destination,ACCESS_READ))
  3015.         {
  3016.             UnLock(FileLock);
  3017.  
  3018.             strcpy(Buffer,Destination);
  3019.             strcat(Buffer,Name);
  3020.  
  3021.                 /* There already is a variable of that
  3022.                  * name in the environment storage
  3023.                  * directory.
  3024.                  */
  3025.  
  3026.             if(FileLock = Lock(Buffer,ACCESS_WRITE))
  3027.             {
  3028.                 UnLock(FileLock);
  3029.  
  3030.                     /* Delete the variable. */
  3031.  
  3032.                 if(!DeleteFile(Buffer))
  3033.                 {
  3034.                     Success = FALSE;
  3035.                     continue;
  3036.                 }
  3037.             }
  3038.  
  3039.                 /* Set the new variable. */
  3040.  
  3041.             if(Length = strlen(Value))
  3042.             {
  3043.                 if(File = Open(Buffer,MODE_NEWFILE))
  3044.                 {
  3045.                     if(Write(File,Value,Length) != Length)
  3046.                     {
  3047.                         Close(File);
  3048.                         DeleteFile(Buffer);
  3049.  
  3050.                         Success = FALSE;
  3051.                     }
  3052.                     else
  3053.                     {
  3054.                         Close(File);
  3055.                         SetProtection(Buffer,FIBF_EXECUTE);
  3056.  
  3057.                         Success = TRUE;
  3058.                     }
  3059.                 }
  3060.                 else
  3061.                     Success = FALSE;
  3062.             }
  3063.             else
  3064.                 Success = TRUE;
  3065.         }
  3066.         else
  3067.             Success = FALSE;
  3068.     }
  3069.  
  3070.     return(Success);
  3071. }
  3072.  
  3073.     /* BumpWindow(struct Window *SomeWindow):
  3074.      *
  3075.      *    Bring a window to the front (and shift the screen
  3076.      *    back to its initial position).
  3077.      */
  3078.  
  3079. VOID
  3080. BumpWindow(struct Window *SomeWindow)
  3081. {
  3082.     if(SomeWindow -> WScreen -> LeftEdge > 0)
  3083.     {
  3084.         if(SomeWindow -> WScreen -> TopEdge > 0)
  3085.             MoveScreen(SomeWindow -> WScreen,-SomeWindow -> WScreen -> LeftEdge,-SomeWindow -> WScreen -> TopEdge);
  3086.         else
  3087.             MoveScreen(SomeWindow -> WScreen,-SomeWindow -> WScreen -> LeftEdge,0);
  3088.     }
  3089.     else
  3090.     {
  3091.         if(SomeWindow -> WScreen -> TopEdge > 0)
  3092.             MoveScreen(SomeWindow -> WScreen,0,-SomeWindow -> WScreen -> TopEdge);
  3093.     }
  3094.  
  3095.     ScreenToFront(SomeWindow -> WScreen);
  3096.  
  3097.     ActivateWindow(SomeWindow);
  3098. }
  3099.  
  3100.     /* BumpDefault():
  3101.      *
  3102.      *    Bring the current default screen to the front.
  3103.      */
  3104.  
  3105. VOID
  3106. BumpDefault()
  3107. {
  3108.     struct Screen *DefaultScreen;
  3109.  
  3110.     if(DefaultScreen = (struct Screen *)LockPubScreen(NULL))
  3111.     {
  3112.         MoveScreen(DefaultScreen,-DefaultScreen -> LeftEdge,-DefaultScreen -> TopEdge);
  3113.  
  3114.         ScreenToFront(DefaultScreen);
  3115.  
  3116.         UnlockPubScreen(NULL,DefaultScreen);
  3117.     }
  3118. }
  3119.  
  3120.     /* WriteIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type):
  3121.      *
  3122.      *    Write data to an IFF file (via iffparse.library).
  3123.      */
  3124.  
  3125. BYTE
  3126. WriteIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type)
  3127. {
  3128.     struct IFFHandle    *Handle;
  3129.     BYTE             Success = FALSE;
  3130.  
  3131.         /* Allocate a handle. */
  3132.  
  3133.     if(Handle = AllocIFF())
  3134.     {
  3135.             /* Open an output stream. */
  3136.  
  3137.         if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
  3138.         {
  3139.                 /* Tell iffparse that this is
  3140.                  * a DOS handle.
  3141.                  */
  3142.  
  3143.             InitIFFasDOS(Handle);
  3144.  
  3145.                 /* Open the handle for writing. */
  3146.  
  3147.             if(!OpenIFF(Handle,IFFF_WRITE))
  3148.             {
  3149.                     /* Push outmost chunk onto stack. */
  3150.  
  3151.                 if(!PushChunk(Handle,'TERM','FORM',IFFSIZE_UNKNOWN))
  3152.                 {
  3153.                         /* Add a version identifier. */
  3154.  
  3155.                     if(!PushChunk(Handle,0,'VERS',IFFSIZE_UNKNOWN))
  3156.                     {
  3157.                         struct TermInfo TermInfo;
  3158.  
  3159.                         TermInfo . Version    = TermVersion;
  3160.                         TermInfo . Revision    = TermRevision;
  3161.  
  3162.                             /* Write the version data. */
  3163.  
  3164.                         if(WriteChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
  3165.                         {
  3166.                                 /* Pop the version chunk, i.e. write it to the file. */
  3167.  
  3168.                             if(PopChunk(Handle))
  3169.                                 Success = FALSE;
  3170.                             else
  3171.                             {
  3172.                                     /* Push the real data chunk on the stack. */
  3173.  
  3174.                                 if(!PushChunk(Handle,0,Type,IFFSIZE_UNKNOWN))
  3175.                                 {
  3176.                                         /* Write the data. */
  3177.  
  3178.                                     if(WriteChunkBytes(Handle,Data,Size) == Size)
  3179.                                         Success = TRUE;
  3180.  
  3181.                                             /* Pop the data chunk. */
  3182.  
  3183.                                     if(PopChunk(Handle))
  3184.                                         Success = FALSE;
  3185.                                 }
  3186.                                 else
  3187.                                     Success = FALSE;
  3188.                             }
  3189.                         }
  3190.                         else
  3191.                             Success = FALSE;
  3192.                     }
  3193.  
  3194.                         /* Seems that we're done, now try to pop the FORM chunk
  3195.                          * and return.
  3196.                          */
  3197.  
  3198.                     if(PopChunk(Handle))
  3199.                         Success = FALSE;
  3200.                 }
  3201.  
  3202.                     /* Close the handle (flush any pending data). */
  3203.  
  3204.                 CloseIFF(Handle);
  3205.             }
  3206.  
  3207.                 /* Close the DOS handle itself. */
  3208.  
  3209.             Close(Handle -> iff_Stream);
  3210.         }
  3211.  
  3212.             /* And free the IFF handle. */
  3213.  
  3214.         FreeIFF(Handle);
  3215.     }
  3216.  
  3217.     if(Success)
  3218.         SetProtection(Name,FIBF_EXECUTE);
  3219.  
  3220.     return(Success);
  3221. }
  3222.  
  3223.     /* ReadIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type):
  3224.      *
  3225.      *    Read data from a `TERM' FORM chunk contained in an IFF file.
  3226.      */
  3227.  
  3228. BYTE
  3229. ReadIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type)
  3230. {
  3231.     struct IFFHandle    *Handle;
  3232.     BYTE             Success = FALSE;
  3233.     struct StoredProperty    *Prop;
  3234.     struct TermInfo        *TermInfo;
  3235.  
  3236.     if(Handle = AllocIFF())
  3237.     {
  3238.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  3239.         {
  3240.             InitIFFasDOS(Handle);
  3241.  
  3242.             if(!OpenIFF(Handle,IFFF_READ))
  3243.             {
  3244.                 /* Collect version number ID if
  3245.                  * available.
  3246.                  */
  3247.  
  3248.                 if(!PropChunks(Handle,&VersionProps[0],1))
  3249.                 {
  3250.                     /* The following line tells iffparse to stop at the
  3251.                      * very beginning of a `Type' chunk contained in a
  3252.                      * `TERM' FORM chunk.
  3253.                      */
  3254.  
  3255.                     if(!StopChunk(Handle,'TERM',Type))
  3256.                     {
  3257.                         /* Parse the file... */
  3258.  
  3259.                         if(!ParseIFF(Handle,IFFPARSE_SCAN))
  3260.                         {
  3261.                             /* Did we get a version ID? */
  3262.  
  3263.                             if(Prop = FindProp(Handle,'TERM','VERS'))
  3264.                             {
  3265.                                 TermInfo = (struct TermInfo *)Prop -> sp_Data;
  3266.  
  3267.                                 /* Is it the file format we are able
  3268.                                  * to read?
  3269.                                  */
  3270.  
  3271.                                 if((TermInfo -> Version > TermVersion) || (TermInfo -> Version == TermVersion && TermInfo -> Revision > TermRevision) || (TermInfo -> Version == 1 && TermInfo -> Revision < 6))
  3272.                                     Success = FALSE;
  3273.                                 else
  3274.                                 {
  3275.                                     struct ContextNode *Chunk = CurrentChunk(Handle);
  3276.  
  3277.                                     if(Chunk -> cn_Size < Size) 
  3278.                                         Size = Chunk -> cn_Size;
  3279.  
  3280.                                     /* The file read pointer is positioned
  3281.                                      * just in front of the first data
  3282.                                      * to be read, so let's don't disappoint
  3283.                                      * iffparse and read it.
  3284.                                      */
  3285.  
  3286.                                     if(ReadChunkBytes(Handle,Data,Size) == Size)
  3287.                                         Success = TRUE;
  3288.                                 }
  3289.                             }
  3290.                         }
  3291.                     }
  3292.                 }
  3293.  
  3294.                 CloseIFF(Handle);
  3295.             }
  3296.  
  3297.             Close(Handle -> iff_Stream);
  3298.         }
  3299.  
  3300.         FreeIFF(Handle);
  3301.     }
  3302.  
  3303.     return(Success);
  3304. }
  3305.  
  3306.     /* PushWindow(struct Window *Window):
  3307.      *
  3308.      *    Push/PopWindow implement a single lifo window stack
  3309.      *    which always updates the window to activate when
  3310.      *    LSHIFT+RSHIFT+RETURN is pressed. This routine will
  3311.      *    push a window on the stack.
  3312.      */
  3313.  
  3314. VOID
  3315. PushWindow(struct Window *Window)
  3316. {
  3317.     if(WindowStackPtr < 5)
  3318.     {
  3319.         WindowStack[WindowStackPtr++] = Window;
  3320.  
  3321.         TopWindow = Window;
  3322.     }
  3323. }
  3324.  
  3325.     /* PopWindow():
  3326.      *
  3327.      *    Remove topmost window from window stack.
  3328.      */
  3329.  
  3330. VOID
  3331. PopWindow()
  3332. {
  3333.     if(WindowStackPtr > 0)
  3334.     {
  3335.         WindowStackPtr--;
  3336.  
  3337.         if(WindowStackPtr)
  3338.             TopWindow = WindowStack[WindowStackPtr - 1];
  3339.         else
  3340.             TopWindow = Window;
  3341.     }
  3342. }
  3343.